c#-使用反射从程序集加载时的不同类型
我有一个包含3个项目的解决方案: 1) GUI可执行文件 2) 具有包含公共API和公共接口的 3) 实现上述接口的类的类库 我试图在API中实现一个资源加载器,这样当GUI调用方法c#-使用反射从程序集加载时的不同类型,c#,.net,reflection,.net-assembly,C#,.net,Reflection,.net Assembly,我有一个包含3个项目的解决方案: 1) GUI可执行文件 2) 具有包含公共API和公共接口的 3) 实现上述接口的类的类库 我试图在API中实现一个资源加载器,这样当GUI调用方法API.Foo()时,我会检查特定文件夹(位于:.\resources)中的每个程序集,其中包含我编译的程序集(#3)的副本。 然后,我想将资源添加到列表中,并使用此列表调用作为接口一部分的函数(每个资源都实现该接口) 所以我所做的是: private List<IResource> m_resource
API.Foo()
时,我会检查特定文件夹(位于:.\resources)中的每个程序集,其中包含我编译的程序集(#3)的副本。
然后,我想将资源添加到列表中,并使用此列表调用作为接口一部分的函数(每个资源都实现该接口)
所以我所做的是:
private List<IResource> m_resources;
public void Foo()
{
string resourceDir = Directory.GetCurrentDirectory() + @"\Resources";
m_resources= new List<IResource>();
foreach (var dllFile in Directory.EnumerateFiles(resourceDir))
{
IResource dllInstance;
if (TryLoadingDLL(Path.Combine(resourceDir, dllFile), out dllInstance))
{
resources.Add(dllInstance);
}
}
}
private static bool TryLoadingDLL(string dllFullPath, out IResource instanceOfDll)
{
instanceOfDll = null;
try
{
Assembly assembly = Assembly.LoadFrom(dllFullPath);
Assembly IResourceAssambly = Assembly.LoadFrom(@"C:\MyProject\MyAPI.dll");
Type[] types = assembly.GetTypes();
foreach (Type type in types)
{
var interfaces = type.GetInterfaces();
var typeOfIResource = IResourceAssambly.GetType("MyProject.IResource");
if (interfaces.Any())
{
var interfaceType = interfaces[0]; //In debuger they have the same GUID
if (interfaceType.IsEquivalentTo(typeOfIResource)) //also tried ==
{
instanceOfDll = Activator.CreateInstance(type) as IResource;
return true;
}
}
}
}
catch (Exception e)
{
Console.Error.WriteLine("Failed to load dll {0}, exception: {1}",dllFullPath, e.Message);
return false;
}
return false;
}
在
问题似乎来自于类型,因此我尝试更换
var typeOfIResource = IResourceAssambly.GetType("MyProject.IResource");
与
结果是现在它没有找到任何东西,即interfaceType.IsEquivalentTo(typeOfIResource)
总是false。
当我使用调试器查看这些类型时,它们看起来完全相同,所以我不知道问题出在哪里
首先,这是一种好的做法吗?我希望其他开发人员向我提供他们的程序集,如果他们实现了IResource接口,则使用反射创建实例并调用所需的方法
第二个也是更重要的一个问题是什么?我该如何解决
谢谢 Look system.component,自.NET 4以来,框架MEF已被集成
此框架允许您在接口的每个实现上使用属性[Export(typeof(interface))]标记,而不考虑dll,并使用目录系统加载它们。(文件夹有一个,这让我想起了过去;我在写的第一个.NET程序中遇到了同样的问题,那一定是15年前的事了 问题是.NET具有不同的“绑定上下文”,其中可以加载类型,“加载”和“加载自”加载到不同的上下文中。运行时会将两个不同上下文中的“相同”类型视为不同的类型,并且不能在它们之间强制转换 这是关于堆栈溢出的一个相当常见的问题;如果您搜索这些术语,您应该会找到一些解释和可能的解决方案的示例。例如,以下示例: 此外,这篇来自.NET早期的博客文章可能有助于解释设计
最后,另一个答案是正确的;如果你想构建一个插件系统,我建议不要从头开始。使用MEF或MAF或其他专门为解决你的问题而设计的系统。加载程序集可能是你最不担心的事情;假设你一定生活在一个第三方插件可能敌对的世界里?解决这个安全问题很难解决,所以让其他人来帮你解决。有什么特别的原因你不只是为了这个而使用
MEF
吗?我不熟悉MEF。我们想要这个设计的原因是可伸缩性。将来添加的程序集将是我们自己的,它们代表了计算同一事物的不同方式,例如在所有的方法都返回了一个答案之后,我们以某种方式混合了结果。好吧,这里有一个愚蠢的问题。它们是否真的引用了相同的接口(在一些常见的程序集中)或者他们只是有一份文件的副本吗?我会更容易地调查MEF。我会调查的,谢谢。他们都在同一个解决方案下,从解决方案内部引用,但我认为他们使用的是本地副本:/很快就会更新。这很尴尬……我确实在:|@BradleyDotNet上有副本本地标志,谢谢你的支持umb问题:P
{System.InvalidCastException: Unable to cast object of type 'MyProject.MyFirstResource' to type 'MyProject.IResource'.
var typeOfIResource = IResourceAssambly.GetType("MyProject.IResource");
var typeOfIResource = typeof(MyProject.IResource);