Search code examples
c#reflectionassembliesreflection.emitreflector

Passing class objects across different assembly versions


The scenario goes like this -

  • I have an assembly say 'MyAssembly'. An interface say 'IMyInterface' is defined in this assembly.
  • In the same assembly i have one class(MyClass) with a method define in it as :

public void MyMethod( IMyInterface object ) { }

  • Now in my project, i have created an interface with the same name and exact properties as exposed by the interface "IMyInterface" in 'MyAssembly'.
  • I have a class which extends this interface(the one which i have created in my project) and i want to pass the object of that class as a parameter to the method "MyMethod" in different assembly using reflection.

Issue is -

  • When i try to invoke the method using reflection, i got this exception that "Cannot convert object to type IMyInterface".

Code -

Assembly myAssembly = Assembly.LoadFrom("MyAssembly");
object classObject = myAssembly.CreateInstance("MyClass");
Type classType = myAssembly.GetType("MyClass");
MethodInfo myMethod = classType.GetMethod("MyMethod", BindingFlags.Instance);

// Creating an object of class in the latest assembly and need to pass this
// to method in assembly with different version.
ClassExtendingMyInterface obj= new ClassExtendingMyInterface ();

myMethod.Invoke(classObject, new object[] { obj});

If, i am getting it right, this is because object created is in different assembly and the parameter expected by the method is of its own assembly.

Another approach i thought of was to create my own dynamic method in the class which will accept the object of my class.

I have tried to google for and come across through Reflection.Emit or RunSharp to dynamically create your own class. But, we can use this only in our dynamically generated Assemblies but can't create dynamic methods or class in already existing assembly.

I know generating assemblies at runtime is ain't good approach. But i can't think of anything now. Thanks for any help.


Solution

  • You are battling something called "Type identity", a very important DLL Hell counter-measure in the .NET framework. A type isn't just identified by its namespace name and type name, it also includes attributes of the assembly from which it came from. Specifically the assembly display name, [AssemblyVersion], [AssemblyCulture], PublicKeyToken and (indirectly) ProcessorArchitecture. You can see the 'real' type name with the Type.AssemblyQualifiedName property. The System.String class for example is System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

    This stops you from faking a type in another assembly unless you can give that assembly the exact same attributes. Much easier is to simply use the existing assembly, should be no problem in your case since you only use an interface.

    Notably is that this requirement was relaxed somewhat in .NET 4. Types that were auto-generated from a COM type library are equivalent if their name and [Guid] matches. Which helped eliminate PIAs and implement the "Embed interop types" feature. Nothing that applies in your case.