跨越不同的程序集版本传递类对象

时间:2012-01-15 16:00:49

标签: c# reflection assemblies reflection.emit reflector

情景是这样的 -

  • 我有一个组件说'MyAssembly'。接口说'IMyInterface'在此程序集中定义。
  • 在同一个程序集中,我有一个类(MyClass),其中的方法定义为:
  

public void MyMethod(IMyInterface object){}

  • 现在,在我的项目中,我创建了一个界面,其名称和属性与“MyAssembly”中的“IMyInterface”界面所显示的相同。
  • 我有一个扩展此接口的类(我在项目中创建的接口),我希望将该类的对象作为参数传递给使用反射的不同程序集中的方法“MyMethod”。

问题是 -

  • 当我尝试使用反射调用方法时,我遇到了“无法将对象转换为IMyInterface类型”的异常。

代码 -

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});

如果,我说得对,这是因为创建的对象是在不同的程序集中,并且该方法所期望的参数是它自己的程序集。

我想到的另一种方法是在类中创建我自己的动态方法,它将接受我的类的对象。

我尝试过google并通过 Reflection.Emit RunSharp 来动态创建自己的类。但是,我们只能在动态生成的程序集中使用它,但不能在现有程序集中创建动态方法或类。

我知道在运行时生成程序集并不是一个好方法。但我现在想不出任何事情。谢谢你的帮助。

3 个答案:

答案 0 :(得分:6)

你正在与一种名为“Type identity”的东西作斗争,这是.NET框架中一个非常重要的DLL Hell对策。类型不仅由其名称空间名称和类型名称标识,还包括它来自的程序集的属性。具体是程序集显示名称,[AssemblyVersion],[AssemblyCulture],PublicKeyToken和(间接)ProcessorArchitecture。您可以使用Type.AssemblyQualifiedName属性查看“真实”类型名称。例如,System.String类是System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

这会阻止您伪造另一个程序集中的类型,除非您可以为该程序集提供完全相同的属性。更简单的是简单地使用现有的程序集,因为你只使用一个接口,所以在你的情况下应该没问题。

值得注意的是,此要求在.NET 4中有所放松。如果名称和[Guid]匹配,则从COM类型库自动生成的类型是等效的。这有助于消除PIA并实施“嵌入互操作类型”功能。没有什么适用于您的情况。

答案 1 :(得分:1)

下面:

  

现在,在我的项目中,我创建了一个界面,其名称和属性与“MyAssembly”中的“IMyInterface”界面所显示的相同。

存在问题;声明一个同名的界面是不够的。类型由它们的组件确定范围;也就是说,CLR是一个完全不同的界面。

而是将引用添加到原始程序集,并实现已定义的接口。它应该只定义一次。

答案 2 :(得分:1)

如果我理解你的问题,我相信你想在他们自己的程序集中定义你的接口,然后从其他两个中的每一个中引用公共接口程序集。这样,每个程序集都引用了SAME接口定义:

创建并构建MyInterfaces dll:

namespace MyInterfaces
{
    public interface IMyInterface
    {
        void SharedMethod();
    }
}

然后在另一个项目中创建第一个程序集,并设置对为MyInterfaces创建的dll的引用。创建您的类,注意模块顶部的“using”语句:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MyInterfaces;

namespace MyFirstProject
{
    public class MyClass1
    {
        public void MyMethod(IMyInterface SomeObject) { }
    }
}

现在,我相信您的动态对象创建应该有效,因为两个对象都实现了“MyInterfaces”中定义的相同接口。