Casting to base class throws InvalidCastException

Go To StackoverFlow.com

3

One of my assemblies contains the following 'provider' types:

InheritanceTree

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?

2012-04-05 01:28
by Gustavo Mori
what is the value of the variable typeName ? read from the XML or a const string value "DeviceInfoProvider" - llj098 2012-04-05 02:36
are all these types in the same assembly - Mike Zboray 2012-04-05 03:10
@mikez: the types loaded from XML don't need to be all in the same assembl - Gustavo Mori 2012-04-05 19:12
@llj098: yes, it's read from the XML. I've updated the question - Gustavo Mori 2012-04-05 19:13


2

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.

2012-04-05 06:20
by Mike Zboray
Thanks for the explanation and the link. Giving the assembly a strong name did the trick - Gustavo Mori 2012-04-05 20:44


0

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

2012-04-05 02:22
by Sam Rueby
so, what is the return value of the Invoke method - llj098 2012-04-05 02:32
You got me. http://msdn.microsoft.com/en-us/library/6ycw1y17.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
If you further filter your Linq expression to sort out types that do not derive from DeviceInfoProvider, do you still get the same type you were looking for - Sam Rueby 2012-04-05 02:40
The documentation on 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
Ads