IsAssignableFrom(甚至ImplementInterface)如何工作

时间:2017-01-30 21:49:51

标签: c# .net types match

我在c#中有一个源自stackoverflow的插件系统。 关键部分是Assembly.LoadFile,Type.IsAssignableFrom和Activator.CreateInstance。它有效,但是我不完全理解IsAssignableFrom如何识别来自外部组件的类型负载。 说,我有

public interface PluginInterface 
{
    int calculateSomething();
}

我已将其编译成PluginInterface.dll。

PluginInterface.dll是示例插件中的引用,例如:

public class CalculateOnePlugin : PluginInterface
{
    public int calculateSomething() { return 1; }
}

它被编译成CalculateOnePlugin.dll。

现在,创建一个引用PluginInterface.dll的应用程序并尝试加载并使用CalculateOnePlugin.dll:

var pluginAssembly = Assembly.LoadFile("CalculateOnePlugin.dll");
Type interfaceType = typeof(PluginInterface);
Type[] typesInLoadedAssembly = pluginAssembly.GetTypes();
Type pluginType = null;
foreach (var typeInLoadedAssembly in typesInLoadedAssembly)
    if (interfaceType.IsAssignableFrom(typeInLoadedAssembly)) // ???
    {
        pluginType = typeInLoadedAssembly;
        break;
    }
if (pluginType!=null) 
{
    PluginInterface pi = (PluginInterface)Activator.CreateInstance(pluginType);
    // and do what you want with that plugin object
}

我的问题是IsAssignableFrom如何识别和匹配从两个外部程序集加载的类型? IsAssignableFrom考虑了哪些汇编或类属性?

如果我复制PluginInterface的源代码并将其编译成(例如)AnotherPluginInterface.dll并在构建CalculateOnePlugin.dll时使用此引用,那么它将无法正常工作。所以类型匹配不仅仅关心方法签名,例如,它知道程序集的来源和类型。

当我为应用程序和插件使用两个不同版本的PluginInterface时(让我们说后者添加了一个方法)它再次无法工作,所以两个dll的起源不是足够的,它必须有一些版本的东西。

但是简单地在两个用法(app和插件)之间重新编译PluginInterface并不会造成混乱,它可以工作。

PluginInterface.dll的GUID是否包含在CalculateOnePlugin.dll的引用中,这就是IsAssignableFrom知道它们是否相同的方式?或类似哈希的值用于类型?或两者兼而有之?

3 个答案:

答案 0 :(得分:2)

在引擎盖下进行了一个复杂的装配解析过程,其中引用的类型要么映射到已经加载的装配,要么导致动态加载必要的装配。当您加载插件时,这可能会有点棘手,特别是如果您有多个位置,其中存在引用的程序集。这可能导致奇怪的情况,例如同一个程序集的两个副本被加载(一个来自您的主文件夹,另一个来自您的插件的文件夹),然后由于所有这些类型的两个不同的不兼容副本被加载而导致运行时错误。

实际的匹配过程通常使用George Vovos答案中提到的完全限定名称,尽管binding redirects之类的内容会使图片复杂化。

您可以使用AppDomain.AssemblyResolve事件自定义程序集解析过程。如果你正在创建一个插件系统,那么值得对组装解决过程进行一些研究,因为有一些问题,特别是如果你做的事情,比如重新加载插件'live'的更新版本。

答案 1 :(得分:1)

您可以自己检查源代码 IsAssignableFrom调用ImplementInterface(Type ifaceType)来检查类型是否实现了接口。

现在,每个类型(类/接口/结构)都在程序集中定义 每个程序集都有Fully Qualified Name,因此即使您复制粘贴源代码,我们也知道定义接口的位置(哪个程序集)

答案 2 :(得分:1)

  

我的问题是IsAssignableFrom如何识别和匹配从两个外部程序集加载的类型? IsAssignableFrom?

考虑了哪些汇编或类属性

基本上存在等价比较。

Type来自名为RunTimeType的类。

RunTimeType有一个Equality运算符,它执行如下检查:

 return RuntimeTypeHandle.IsEquivalentTo(this, otherRtType);

不幸的是RuntimeTypeHandle.IsEquivalentTo被标记为CLR核心的一部分并且无法反映出来,因此我无法准确地告诉您它的外观或代码的作用。

然而,根据this article entitled "Anatomy of a .NET Assembly"

  

使用表示类型名称和完全限定程序集名称的字符串(例如,MyNs.MyType, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0123456789abcdef)存储类型值。如果类型在当前程序集或mscorlib中,则只能使用类型名称。

因此,程序集名称,区域性,版本,命名空间和公钥令牌似乎都匹配,以便唯一地标识类型。