我正在开发一个插件系统,用于加载包含在指定文件夹中的.dll。然后我使用反射来加载程序集,遍历它们包含的类型并识别实现我的IPlugin
接口的任何类型。
我正在使用类似于以下内容的代码进行检查:
foreach(Type t in myTypes )
{
if( typeof(IPlugin).IsAssignableFrom(t) )
{
...
}
}
出于某种原因,IsAssignableFrom()在返回true时保持返回false。我已经尝试通过显式赋予它一个应该传递的类型替换t
,并且它工作正常,但由于某种原因它不能处理从加载的程序集返回的类型。为了使事情变得更奇怪,代码在我的同事的机器上工作正常,但在我的机器上却没有。
有没有人知道任何可能导致这种行为的事情?
由于
答案 0 :(得分:28)
当包含当前程序集引用的类型IPlugin的程序集与包含您正在迭代的类型的程序集引用的程序集不匹配时,通常会发生这种情况。
我建议你打印:
typeof (IPlugin).Module.FullyQualifiedName
和
foreach (var type in t.GetInterfaces ())
{
Console.WriteLine (type.Module.FullyQualifiedName)
}
查看不匹配的位置。
答案 1 :(得分:7)
其他一些答案提到IsAssignableFrom
方法名称缺乏明确性。我同意,因此以错误的方式使用它。
尝试在代码中使用反转对象进行一些实验,看看它是否有效。例如:
替换:
if (typeof(IPlugin).IsAssignableFrom(t))
使用:
if (t.IsAssignableFrom(typeof(IPlugin)))
通过这样做,我不仅让它起作用,而且开始了解这种方法实际上做了什么。
答案 2 :(得分:6)
当接口在单独的程序集中定义为实现类型时,我遇到了同样的问题。 从根文件夹中迭代和加载程序集,其中包含带有类和带接口的dll的dll导致类型不匹配,如上所述。
一种解决方案是将LoadFrom()
更改为LoadFile()
LoadFrom
方法有一些缺点,那就是其中之一:
如果已加载具有相同标识的程序集,则即使指定了不同的路径,LoadFrom也会返回已加载的程序集。
另一种解决此问题的方法是将所有实现接口类型的dll放入单独的文件夹中,而不是复制引用的程序集(CopyLocal = False
),这样Assembly.LoadFrom
就不会在内存中加载包含接口的dll。
答案 3 :(得分:1)
有时,动态程序集引用另一个程序集会出现问题。
在组件上禁用本地副本是一件简单的事情(在visual studio中右键单击引用并将copy local设置为false)。这样可以更容易确定程序集所在的目录。
您还可以实现程序集解析程序,以防.NET不知道如何初始化该类型。
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler([Resolve Function]);
答案 4 :(得分:0)
我在Java中工作,它具有相同的API方法,在阅读代码时我无法理解它(出于某种原因);因此,我总是反过来看,因为在你的情况下,“t可以分配给IPlugin。”因此,如果C#有“是”,如Jonathon建议的那样,我会一直使用它 - 当在Java中反映时“instanceof”不起作用类对象,仅对象的实例。
答案 5 :(得分:-1)
如果您使用的是.net core,并且正在遵循 this link 上的教程,请确保您记得将其添加到插件项目中
<ItemGroup>
<ProjectReference Include="..\PluginBase\PluginBase.csproj">
<Private>false</Private>
<ExcludeAssets>runtime</ExcludeAssets>
</ProjectReference>
</ItemGroup>
,如链接中所述。如果没有,则会出现上述错误。 This also helped me
答案 6 :(得分:-2)
当应用于测试继承或检测接口实现时,Type.IsAssignableFrom方法的名称含糊不清且令人困惑。以下用于这些目的的包装器会更有意义:
public static bool CanBeTreatedAsType(this Type CurrentType, Type TypeToCompareWith)
{
// Always return false if either Type is null
if (CurrentType == null || TypeToCompareWith == null)
return false;
// Return the result of the assignability test
return TypeToCompareWith.IsAssignableFrom(CurrentType);
}
然后,人们可以拥有更易理解的应用程序代码,例如:
bool CanBeTreatedAs = typeof(SimpleChildClass).CanBeTreatedAsType(typeof(SimpleClass));
CanBeTreatedAs = typeof(SimpleClass).CanBeTreatedAsType(typeof(IDisposable));
此方法代替'is'关键字的优点是它可以在运行时用于测试未知的任意类型,而'is'关键字(和通用的Type参数)需要编译时知识特定类型。