Casting Error with Reflection - c#

I have an application that uses plugins that are managed via an interface I then dynamically load the plugin classes and cast them to the interface to work with them.
I have the following line of code, assume that IPlugin is my interface.
IPlugin _plugin = (IPlugin)Activator.CreateInstance(oInfo.Assembly, oInfo.FullyQualifiedName)
This should be pretty simple, create the instance and cast it to the interface. I know that the assembly and fully qualified name values are correct, but I am getting the following exception.
Exception=
System.InvalidCastException: Unable to
cast object of type
‘System.Runtime.Remoting.ObjectHandle’
to type
‘MyNamespace.Components.Integration.IPlugin’.
at
MyNamespace.Components.Integration.PluginProxy..ctor(Int32
instanceId)
Any ideas what could cause this?

The exception indicates that you're getting an ObjectHandle, which suggests that your object is being marshaled and must be unwrapped.
Try the following
ObjectHandle marshaled_plugin = (ObjectHandle)Activator.CreateInstance(oInfo.Assembly, Info.FullyQualifiedName);
IPlugin plugin = (IPlugin)marshaled_plugin.Unwrap();

As you can see in the documentation, this overload returns an ObjectHandle object that wraps the new instance.
The ObjectHandle cannot be casted directly to your interface.
Instead, you need to call the Unwrap method, like this:
IPlugin _plugin = (IPlugin)Activator.CreateInstance(...).Unwrap();

Related

How to instantiate an interface, with a generic parameter

I have some classes that implement the interface below:
ISearchBase<T>
But I don't know which class will be instantiated, so I let "the user decide", like the example below:
var objectResponse = Activator.CreateInstance(Type.GetType(ResponseNamespace));
The problem is:
Each those classes has a return and I'm trying to use like this:
var object = (ISearchBase<objectResponse >)
Activator.CreateInstance(Type.GetType(Namespace));
But the compiler won't let me do this... What can I do?
The error is:
The type or namespace name 'objectResponse' could not be found.
When you do var object = (ISearchBase<X>)... you must know the type X at compile time. The var keyword is just short-hand for the compiler to infer the type. So, you cannot use a run-time type to resolve for X.
You haven't shown what you what to do with the object after you've created it. It is certainly possible to call a generic method using reflection to allow you to type-safe code, but I can't tell if that will be useful to you or not without seeing more code.

Calling method from COM Object using Reflection

In order to allow compatibility with another project that is written in .Net 2.0, we have had to come up with a COM interop (the newer application is in .Net 4.0). This would work because the 2.0 process would be able to use SxS execution with .Net 4.0. In order to have a COM interop from what I understand I have to do something like this:
Type myClass = Type.GetTypeFromProgID("Net4Assembly.Assembly4");
object myInstance = Activator.CreateInstance(myClass);
IAssembly4 assembly4Interface = (IAssembly4)myInstance;
assembly4Interface.CallMethod();
I have already created the COM component and registered it and this works fine. But the problem is that since the project written in 2.0 is outside our department, I want to find a way of doing the casting in line 3 above using reflection. So far I have found a suggestion in Invoke method using Reflection on COM Object
But this doesn't work for me since when I get all the methods of the object in "myInstance" which is of type COMObject, I can only see the methods that are mentioned in that link. I get this error:
Unknown name. (Exception from HRESULT: 0x80020006 (DISP_E_UNKNOWNNAME))
I think I should somehow cast the COMObject to the interface and then I would have access to the methods? Shouldn't I be able to extract the interface from the COMObject, then call the method using reflection? I tried GetInterfaces() from the COMObject but nothing is returned.
I am not sure if this will work but assuming you have No Misspelled Assembly Name try something like this
Type myClass = Type.GetTypeFromProgID("Net4Assembly.Assembly4");
object myInstance = Activator.CreateInstance(myClass );
//object[] arguments = new object[] //add parameters if youre assembly expects them here
object result = myClass .InvokeMember("SubtractTwoNumbers", BindingFlags.InvokeMethod,
null, myInstance, arguments);

Unable to cast System.Runtime.Remoting.ObjectHandle

In my code I have an interface - lets say its called InterfaceName and its implementation called InterfaceImpl. Now when I dynamically try to obtain the InterfaceImpl using the following code:
object obj = Activator.CreateInstance("ProjectName","ProjectName.Folder.InterfaceImpl");
InterfaceName in = (InterfaceName)obj; //Error pops up here
I get the following error
Unable to cast object of type 'System.Runtime.Remoting.ObjectHandle' to type 'ProjectName.Folder.InterfaceName'.
Any suggestions on what might be going wrong ?
If you read the documentation about the method you are calling, it returns
A handle that must be unwrapped to access the newly created instance.
Looking at the documentation of ObjectHandle, you simply call Unwrap() in order to get the instance of the type you are trying to create.
So, I guess your real issue is... Why?
This method is designed to be called in another AppDomain, and the handle returned back to the calling AppDomain, where the proxy to the instance is "unwrapped".
What? That doesn't explain why?
Only two types can cross an AppDomain barrier. Types that are serializable (of which copies are created), and types that extend MarshalByRefObject (of which proxies are created and passed). ObjectHandle extends MarshalByRefObject, and so can cross that AppDomain barrier, whereas the type which they are representing may not extend MBRO or be serializable. This method ensures you can get that type instance across the barrier, no matter what.
So, if you are just trying to instantiate a type, you might want to look at a different overload of CreateInstance. Or just unwrap the result.
var obj = Activator.CreateInstance("A","A.B.C") as ObjectHandle;
InterfaceName in = (InterfaceName)obj.Unwrap();

InvalidCastException when creating an instance using assembly.CreateInstance

I'm looking for an explanation for the following -
I have an assembly I'm loading using
Assembly assembly = Assembly.LoadFrom(filename);
I then loop on all the types in the assembly, and wish to try and find out if a type implements a particular interface and if so I want an instance of that type, I've tried several things which did not work, but when I fell back to the most basic (and probably inefficient) way, I realised there's something more fundamental I don't understand -
foreach (Type t in assembly.GetTypes())
{
foreach (Type i in t.GetInterfaces())
{
if (i.FullName == pluginInterfaceType.FullName)
{
object o = assembly.CreateInstance(t.ToString());
IInterface plugin = (IInterface)o;
That last line causes an InvalidCastException, despite the fact that the type created definitely implements that interface.
Further more - if I use Activator.CreateInstance instead of Assembly.CreateInstance (which I don't want to do), casting to the interface works just fine.
This is most probably because the interface you are casting to is not the same you find in the class.
Either because there is more the one interface with the same name, or because you loaded it more then once. For instance, because it is defined in the assembly you are dynamically loaded, and you try to cast it to the one that is statically bound.
The InvalidCastException should contain more details, like 'cannot cast x to y'.
My guess is that the assembly containing IInterface that you are loading is not exactly the same as the one your code was built against, maybe it's a local copy of a non strongly-named assembly.

Dynamically Loading a DLL

I am trying to simply load a dll written in C# at run time and create an instance of a class in that dll.
Assembly a = Assembly.LoadFrom(#"C:\Development\DaDll.dll");
Type type = a.GetType("FileReleaseHandler", true);
TestInterface.INeeedHelp handler = Activator.CreateInstance(type) as TestInterface.INeeedHelp;
No errors are thrown, and if I step through the code I can walk though the FileReleaseHandler Class as it executes the constructor but the value of handler is always null.
What am I missing here? or even is there a better way I should be going about this?
Where is TestInterface.INeedHelp defined? One common problem is if you've got the same interface in multiple assemblies. If both the caller and the dynamically loaded assembly reference the same interface in the same assembly, it should be okay.
One subtlety is that if the assembly is in a different directory to the calling assembly, it may end up loading a different copy of the same assembly, which can be very irritating :(
Try setting the result of Activator.CreateInstance to an object directly, and not casting.
It's possible FileReleaseHandler does not implement TestInterface.INeeedHelp, in which case, this will be set to null via the "as TestInterface.INeeedHelp".
Check the assemblies that are loaded into the application domain. Are there two assemblies with the TestInterface.INeedHelp interface in it? My suspicion is that the LoadFrom is binding this created object to a different TestInterface.INeedHelp than the one to which you are trying to cast. Try doing a normal downcast rather than a so-called "safe" cast and see what error you get.
The problem is that the LoadFrom method loads the dll into "LoadFrom" context which is different from the default context. The rules of type resolution for the types in this context differ from the ones you are used to. It is possible that the INeedHelp interface as defined in your main module from the standpoint of the runtime is different from the interface with the same name as coming from the LoadFrom context. This will cause the cast (as TestINterface) return null.
To see if this is the case try to assign the result to an object.
I would do something like :
Assembly a = Assembly.LoadFrom(#"C:\Development\DaDll.dll");
object obj = a.CreateInstance("fullClassName",other params) as IMyType
//(if it implements an interface you referenced)

Categories

Resources