One of my assemblies contains the following 'provider' types:
I also have an XML file which holds provider info using the DeviceInfoProvider
base class. A simplified version looks like this:
<DeviceInfoProvider Type="SbRioI2CProvider" Assembly="assembly.dll" >
</DeviceInfoProvider>
<DeviceInfoProvider Type="GenericProvider" Assembly="assembly.dll" >
</DeviceInfoProvider>
At runtime, I map XML fields to my variables:
assembly.dll ⇒ assemblyPath
Type ⇒ typeName
And after reading the XML, use the following code to instantiate my types:
var assembly = Assembly.LoadFrom(assemblyPath);
var type = (from t in assembly.GetTypes()
where t.IsPublic && t.Name == typeName
select t).FirstOrDefault();
if (type != null)
{
instance = type.GetConstructor(Type.EmptyTypes).Invoke(null);
}
As expected, this generates my objects appropriately.
The problem comes when I try to cast instance as a base class object:
using (var provider = instance as DeviceInfoProvider)
{
// provider is null!
}
The runtime type of instance
is the expected derived class, yet I am unable to successfully cast it to its base type.
What am I missing?
Your problem may be that you are creating instances (GenericProvider, SbRioI2CProvider) from types in assembly.dll in the LoadFrom context. Then you are trying to cast by name to a type (DeviceInfoProvider) in that assembly. This implicitly uses the Load context. Types from the same assembly but loaded in different contexts are considered different types by the runtime, so the cast fails and you get null. This article provides some additional explanation of assembly binding contexts.
To get this cast to succeed, you need to get the Assembly
that is loaded in the LoadFrom context into the Load context. There are a couple ways to do this. One way is to put the assembly in the GAC. Another is to remove the assembly.dll from the applicationbase so that it will not be found by probing. Then use the AppDomain.AssemblyResolve event to load the Assembly
that you got via LoadFrom.
Invoking the constructor of a reflected type doesn't create an instance of it.
To create an instance of a reflected type, call Activator.CreateInstance
.
It looks like this line should be:
if (type != null) {
instance = Activator.CreateInstance(type)
}
This will cause instance
to be of type object
, but now you can cast it to whatever you want.
See: http://msdn.microsoft.com/en-us/library/wccyzw83.aspx
An instance of the class associated with the constructor
. I've never seen an instance of a reflected type created that way before - Sam Rueby 2012-04-05 02:35
DeviceInfoProvider
, do you still get the same type you were looking for - Sam Rueby 2012-04-05 02:40
ConstructorInfo.Invoke
notes that Activator.CreateInstance
should be used to "create an instance of a value type that has no instance constructors". Still, I tried it, and it didn't make a differenc - Gustavo Mori 2012-04-05 19:18
typeName
? read from the XML or a const string value "DeviceInfoProvider" - llj098 2012-04-05 02:36