I have a set of classes, each one is a different strategy to do the same work.
namespace BigCorp.SuperApp
{
public class BaseClass { }
public class ClassA : BaseClass { }
public class ClassB : BaseClass { }
}
The choice of which strategy to use is configurable. I want to configure only the class name 'ClassB' instead of the full type name 'BigCorp.SuperApp.ClassB' in the app.config file.
<appConfig>
<SuperAppConfig>
<Handler name="ClassB" />
</SuperAppConfig>
</appConfig>
However, the reflection calls fail because they expect the full type name, particularly
Type t = Type.GetType("ClassB"); // results in t == null
BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails
How can I get this to work while configuring only the class name? Concatenate the namespace to the class name for full type name? Is there another reflection call that works?
If you think this is useless and I should expect the configuration to contain the full type name, I am open to that solution! Just provide rationale to convince me.
(I will not be loading a type from outside this assembly/namespace)
Either use the assembly-qualified-name, or get hold of the Assembly and use Assembly.GetType(name). In this case, since you want the types in the config file, assembly-qualified is a valid way to go - but since you know all your types are in the same assembly:
Assembly assembly = typeof(SomeKnownType).Assembly; // in the same assembly!
Type type = assembly.GetType(name); // full name - i.e. with namespace (perhaps concatenate)
object obj = Activator.CreateInstance(type);
The static Type.GetType(string) has probing rules that often cause confusion... it looks at the calling assembly, and a few system assemblies - but not all loaded assemblies.
Since you know all classes will be coming from the same namespace, configure it once and use that:
<appConfig>
<SuperAppConfig handlerNamespace="BigCorp.SuperApp">
<Handler class="ClassB" />
</SuperAppConfig>
</appConfig>
Edit: I changed name to class to better denote the meaning of that attribute.
(I will not be loading a type from outside this assembly/namespace)
because of the above line, it is safe to assume that you know what the namespace is. Couldn't you do something like:
Type t = Type.GetType("Namespace." + className);
BaseClass c = Activator.CreateInstance(t) as BaseClass;
If you expect to possibly be able to add additional strategy classes to be loaded in the future, perhaps via an additional assembly, you would need to fully qualify your class name. This is recommended anyway, since you would be able to provide enhanced extendability for your application.
I'm going with the full type name in the application configuration. Below is a slightly more complete, but still trivial example
<SuperAppConfig>
<ObjectConfig provider="BigCorp.SuperApp.ClassA">
<add name="one" />
<add name="two" />
</ObjectConfig>
</SuperAppConfig>
And the factory class that actually creates this
private static Assembly a = typeof(IFactoryObject).Assembly;
public static IFactoryObject CreateObject(String providerName)
{
Type t = a.GetType(providerName)
IFactoryObject o = Activator.CreateInstance(t) as IFactoryObject;
return o;
}
BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails
Might also result from the fact, that CreateInstance does not return an instance of BaseClass, rather than an instance of BaseClass wrapped into an ObjectHandle.
Cast into your BaseClass after you used the UnWrap method.
Related
I'm reading a book which says:
Obtaining a TypeInfo object forces the CLR to resolve the type by ensuring that the assembly
that defines the type is loaded. This can be an expensive operation that can be avoided if all you need
are type references (Type objects). However, after you have a TypeInfo object, you can query many
of the type’s properties to learn more about it. Most of the properties, such as IsPublic, IsSealed,
IsAbstract, IsClass, IsValueType, and so on, indicate flags associated with the type.
below is the some source code:
public abstract class Type : ... {
public bool IsPublic { get; }
public bool IsSealed { get; }
public bool IsAbstract { get; }
...
}
public static class IntrospectionExtensions {
public static TypeInfo GetTypeInfo(this Type type);
}
public abstract class TypeInfo : Type {
...
}
My question is:
The author seems to mean that you need to call GetTypeInfo method in a Type object which causes CLR to load the assembly first, then you can query IsPublic, IsSealed, IsAbstract, IsClass, IsValueType.So it seems that you cannot query those properties before calling GetTypeInfo method. But my understanding for assembly metatable is, a referenced type 's basic information such as if the type is a class, abstract etc is stored in the referencing assembly's metatable, so when the code in the referencing assembly wants to query the basic information of a type that's in an external assembly, the CLR just needs to read the metatable in the referencing assembly which is the current executing assembly, CLR doesn't need to load/read the external(referenced) assembly, is my understanding correct?
TypeInfo is part of Reflection. Everything in Reflection tends to be an expensive operation.
TypeInfo is used for late binding - meaning your code doesn't know what type it is working with. IE, you are working with Generics or Plugins.
If you aren't doing late binding (IE, you code knows exactly what 'type' you are working with, you don't need to do anything like TypeInfo.
Edit: I haven't read this, but this article (or maybe some google research) on why reflection is slow can help you understand your question: https://mattwarren.org/2016/12/14/Why-is-Reflection-slow/
Is there a way to create an instance of a class based on the fact I know the name of the class at runtime. Basically I would have the name of the class in a string.
Take a look at the Activator.CreateInstance method.
Its pretty simple. Assume that your classname is Car and the namespace is Vehicles, then pass the parameter as Vehicles.Car which returns object of type Car. Like this you can create any instance of any class dynamically.
public object GetInstance(string strFullyQualifiedName)
{
Type t = Type.GetType(strFullyQualifiedName);
return Activator.CreateInstance(t);
}
If your Fully Qualified Name(ie, Vehicles.Car in this case) is in another assembly, the Type.GetType will be null. In such cases, you have loop through all assemblies and find the Type. For that you can use the below code
public object GetInstance(string strFullyQualifiedName)
{
Type type = Type.GetType(strFullyQualifiedName);
if (type != null)
return Activator.CreateInstance(type);
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
type = asm.GetType(strFullyQualifiedName);
if (type != null)
return Activator.CreateInstance(type);
}
return null;
}
Now if you want to call a parameterized constructor do the following
Activator.CreateInstance(t,17); // Incase you are calling a constructor of int type
instead of
Activator.CreateInstance(t);
I've used this method successfully:
System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(string className)
You'll need to cast the returned object to your desired object type.
Probably my question should have been more specific. I actually know a base class for the string so solved it by:
ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));
The Activator.CreateInstance class has various methods to achieve the same thing in different ways. I could have cast it to an object but the above is of the most use to my situation.
To create an instance of a class from another project in the solution, you can get the assembly indicated by the name of any class (for example BaseEntity) and create a new instance:
var newClass = System.Reflection.Assembly.GetAssembly(typeof(BaseEntity)).CreateInstance("MyProject.Entities.User");
I know I'm late to the game... but the solution you're looking for might be the combination of the above, and using an interface to define your objects publicly accessible aspects.
Then, if all of your classes that would be generated this way implement that interface, you can just cast as the interface type and work with the resulting object.
For instance, if you store values of various types in a database field (stored as string) and have another field with the type name (i.e., String, bool, int, MyClass), then from that field data, you could, conceivably, create a class of any type using the above code, and populate it with the value from the first field. This of course depends on the type you are storing having a method to parse strings into the correct type. I've used this many times to store user preference settings in a database.
ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));
why do u want to write a code like this? If you have a class 'ReportClass' is available, you can instantiate it directly as shown below.
ReportClass report = new ReportClass();
The code ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass)); is used when you dont have the necessary class available, but you want to instantiate and or or invoke a method dynamically.
I mean it is useful when u know the assembly but while writing the code you dont have the class ReportClass available.
I have a class I am attempting to instantiate through the use of Assembly and Activator, this class implements an interface, however when I run the instance of the class through a conditional that checks that the class implements it, I am getting false. What could be the problem?
My code where I am checking for implementation:
string className = MyClass;
Type type = null;
Assembly assembly = Assembly.LoadFile("#C:\\MyDLL", new Evidence(AppDomain.CurrentDomain.Evidence));
type = assembly.GetType(className);
object instance = Activator.CreateInstance(type);
//never makes it past this conditional
if (!(instance is MyInterface)
{
//It always endsup in here, when it shouldn't.
System.Writeline("ERROR");
}
else{
//This is what needs to happen
}
Code for the class MyClass that is outside the scope of all of this, and in MyDLL
public class MyClass: MyInterface
{
//Contents irrelevent to my problem
}
I am at a loss as to why this is not passing the conditional. Could I be instantiation the class wrong? Also to note I am a huge rookie when it comes to using Assembly/Activator and using interfaces.
Most likely reason - both DLL and your code have own version of MyInterface. This could happen either because
one did not want to spend time to come up with good unique name for interface,
someone decided to share interface as source instead of via assembly reference,
good named interfaces in the different namespaces and you are using the wrong one.
You may be referencing your assembly directly. If so, the types you load dynamically will have the identical name and namespace, but are considered different by the runtime.
I created the Class1.GetChild<T>() where T : DependencyObject extension method in lib1.dll assembly. After that, all assemblies that depends on lib1.dll failed to compile with error:
The type 'System.Windows.DependencyObject' is defined in an assemebly
that is not referenced. You must add a reference to assembly
'WindowsBase' etc...
Why dependent assemblies requires WindowsBase even if they don't use GetChild?
.
To reproduce (vs2010 .net4):
lib1.dll (references WindowsBase)
namespace lib1
{
public static class Class1
{
public static T GetChild<T>(this DependencyObject src) where T : DependencyObject
{
return default(T);
}
}
public static class Class2
{
public static int SomeExtMethod(this string src)
{
return 0;
}
}
}
lib2.dll (references lib1 but not WindowsBase)
using lib1;
class someClass
{
void someFct()
{
"foo".SomeExtMethod(); // error: The type 'System.Windows.DependencyObject'
// is defined in an assemebly that is not referenced.
// You must add a reference to assembly 'WindowsBase' etc..
}
}
.
Update:
I think there's definitly something when mixing generic methods and extension methods. I tried to demonstrate the issue in the following sample:
// lib0.dll
namespace lib0
{
public class Class0 { }
}
// lib1.dll
using lib0;
namespace lib1
{
public static class Class1
{
public static void methodA<T>() where T : Class0 { } // A
public static void methodB(Class0 e) { } // B
public static void methodC(this int src) { } // C
}
public static class Class2
{
public static void methodD(this String s) { }
}
}
// lib2.dll
using lib1;
class someClass
{
void someFct()
{
Class2.methodD(""); // always compile successfully
"".methodD(); // raise the 'must add reference to lib0' error depending on config. see details below.
}
}
A, //B, //C -> compile ok
A, B, //C -> compile ok
//A, B, C -> compile ok
A, //B, C -> raise error
A, B, C -> raise error
//A means methodA is commented. As Damien pointed out, type inference might play some role. Still curious to know the ins and outs.
Your situation has been answered by Microsoft here:
https://connect.microsoft.com/VisualStudio/feedback/details/668498/problem-with-extension-method-in-c-compiler
There are other use-cases as well independent of extension methods which produce this error wrongly.
Consider this:
Define a generic method in a type, say TP1, defined in library say LB1.
Type constrain the generic method on some type defined in some other library LB2.
Define another method in TP1.
Now in your library reference only LB1 and try to call the second method of type TP1
If you don't use TP1 but some other type defined in LB1, you do not get the error.
Also, even if one of the method of type TP1 expects a parameter of the type defined in LB2 (and you do not call this method) it does not produce this error
When one assembly depends on another assembly, the first assembly also depends on all the dependencies of the other--regardless of what is used. Assembly dependencies are effectively decoupled, another version of either assembly can be deployed after compilation, the compiler can't know that under circumstances like this one or more of the dependencies in the second assembly won't be used by the first assembly.
To solve the issue you can simply add a reference to WindowsBase.
Or, as prashanth points out, put the SomeExtMethod into a different assembly so code that uses that doesn't need to take a dependency on WindowsBase.
Update:
If you don't use anything from an assembly, you don't need any of its dependencies. But, as soon as you use one assembly, you need all the dependencies of that assembly as well. This is apparent in the way Visual Studio add references. If you add a reference to an assembly, it will copy all the dependent assemblies (not registered in the GAC) into your debug/release directories along with the assembly you added.
Update:
As to the compile error: that's the way it was written--there may be no other reason. Is it a good idea to get a compile error if you don't reference dependent assemblies? Maybe, you're likely to use something from a reference and that might use something directly from the references references--better a compile error than a deployment error.
Why not a compile error on every non-referenced secondary dependency? Again, it was written that way. Maybe an error here too would be good; but that would be a breaking change and would require really persuasive reasons.
I'm not sure this can be answered by anyone other than someone on the compiler team. I'm now thinking that it's to do with type inference - but whereas §7.6.5.1 Method Invocations talks about inference, §7.6.5.2 Extension method invocations is silent on the matter - despite the fact that inference obviously does take place when searching for applicable extension methods.
I think it's attempting some form of inference before it's performing the comparison on identifiers (which would immediately rule out the extension method since it's got the wrong name). Obviously, it can't perform any form of inference for this type if it's unable to understand the type constraints.
Hence, when you change your type constraint to just class, it now successfully passes over this method - it can infer a type parameter, but it now eliminates this extension method successfully.
When you reference another assembly, I assume the compiler needs to be able to parse any method signatures defined in that assembly, so it knows where to go to find that function if it sees a call to it.
If you replace your GetChild() function with
public static T GetChild<T>(this T src)
{
if (typeof(T) == typeof(DependencyObject)) return default(T);
else return default(T);
}
or something similar to that, it does not require you to include the reference to WindowsBase that you're running into. But if you add where T : DependencyObject to the signature, it does require it.
Effectively, you can use whatever assembly references you want in a project, so long as you don't expose them in any way. Once you expose them, then every other project which uses your library needs to be able to handle them, and thus requires those references themselves.
Maybe ILMerge would solve this problem. The idea is you create 2 dlls and merge them into one. That way you can have a single dll but reference it twice. Then way you can separate the GUI code from other code and only add the reference that you need to the particular project.
The answer is simple. It is because the method is decalre as public. This mean that it is visible to lib2.dll (in your case.) In other word you can call this method.
It also has a constrain that only classes inherited from DependencyObject can call this method. So that is the reason why you need to reference 'WindowsBase'.
Is it possible to get an abstract type from a given Assembly at runtime?
I am currently loading my assembly with:
Assembly assem = Assembly.LoadFrom("MyAssemblyName.dll");
But then I want to do this:
Type t = assem.GetType("Enterprise.Shared_Party_PersonType");
My class is defined as:
public abstract class Shared_Party_PersonType
But type t is returning null.
My final goal is to navigate an abstract class with reflection and get a list
of properties of that abstract class, similar to what they do here: access-to-properties-of-abstract-class-with-reflection
Any help will be very appreciated.
Solution: Turns out that I was loading the wrong version of the DLL, which didn't contain the abstract type I was trying to load. However, now I know that you can navigate and manipulate abstract types with reflection as any other concrete type. Also I learned about Assembly.RefelectionOnlyLoadFrom method thanks to #Fuex to load an assembly in reflection-only context
Yes, you can get any type, even an interface. Just make sure that you specify it's full name, including the namespace:
Type t = assem.GetType("SomeNamespace.AnAbstractClassName", true);
Full example:
using System;
using System.Reflection;
namespace SomeNs
{
public abstract class Foo
{
}
}
public class Program
{
static void Main()
{
var asm = Assembly.GetExecutingAssembly();
var type = asm.GetType("SomeNs.Foo", true);
Console.WriteLine(type);
}
}
Maybe your class is defined inside some other class. In that case you must use a + (plus) instead of a . (dot). Like this:
assem.GetType("OutermostNamespace.InnerNamespace.Enterprise+Shared_Party_PersonType")
where Enterprise is an "outer" class or struct that Shared_Party_PersonType is defined inside.
Otherwise, can you access the source code of MyAssemblyName.dll? Then you might try to se what string n = typeof(Shared_Party_PersonType).FullName returns in there, to check if the type name is really what you presume.
I just need to inspect the abstract type properties recursively to
extract binding paths that meet certain conditions.
Becuase of Assembly.LoadFrom() can have undesiderable effects the best solution if you just need to inspect type informations is to use Assembly.ReflectionOnlyLoadFrom().
So try:
Assembly asm = Assembly.ReflectionOnlyLoadFrom("mypath");
Type t = asm.GetType("FullName");