簡體   English   中英

c# - 使用反射從裝配加載時的不同類型

[英]c# - Different types when loading from assembly using reflection

我有一個包含3個項目的解決方案:1)GUI可執行文件2)包含公共API和公共接口的類庫3)實現上述接口的類的類庫

我正在嘗試在API中實現資源加載器,這樣當GUI調用方法API.Foo()我會檢查特定文件夾(位於:。\\ resources)中的每個程序集,其中包含程序集的副本 I編譯(#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;
}

我實際上一開始就使用了這個,結果相同:

List<Type> derivedTypesList = typses.Where(type => type.GetInterfaces().Contains(IWNAssambly.GetType("MyProject.IResource"))).ToList();
if (derivedTypesList.Count > 0)
{
    instanceOfDll = (IResource)Activator.CreateInstance(derivedTypesList[0]);
    return true;
}

但后來我將其分解,以便我可以輕松調試。

當我運行任何這些片段時,我確實找到了一種實現接口的類型,但是當我嘗試強制轉換它時,我通過as運算符獲取null,並在使用(IResource)轉換時獲得異常。 例外是:

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

結果是現在它根本找不到任何東西,即interfaceType.IsEquivalentTo(typeOfIResource)總是為false。 當我用調試器查看這些類型時,它們看起來完全一樣,所以我不知道是什么問題。

首先,這是一個好習慣嗎? 我希望其他開發人員為我提供他們的程序集,如果他們實現了IResource接口,那么使用反射創建一個實例並調用所需的方法。

第二個也是更重要的是,問題是什么,我該如何解決?

謝謝!!!

這帶回了回憶; 我在我編寫的第一個.NET程序中遇到了同樣的問題,這個程序一定是十五年前的。

問題是.NET有不同的“綁定上下文”,其中可以加載類型,並且“Load”和“LoadFrom”加載到不同的上下文中。 兩個不同上下文中的“相同”類型將被運行時視為不同,並且您無法在它們之間進行轉換。

這是關於Stack Overflow的一個相當常見的問題; 如果您搜索這些術語,您應該找到一些解釋和可能解決方案的示例。 例如,這一個:

從動態加載程序集創建對象並將其強制轉換為接口(.NET 2.0)

此外,這篇來自.NET早期的博客文章可能有助於解釋設計

http://blogs.msdn.com/b/suzcook/archive/2003/09/19/loadfile-vs-loadfrom.aspx

最后,另一個答案是正確的; 如果你想構建一個插件系統,我建議不要從頭開始。 使用MEF或MAF或專門設計的其他系統來解決您的問題。 裝卸組件可能是您最不擔心的; 假設您必須生活在第三方插件可能存在敵意的世界中? 解決安全問題很困難,所以讓別人為你做。

查看system.component,因為.NET 4已經集成了框架MEF。 MEF

此框架允許您在接口的每個實現上通過屬性[Export(typeof(interface))]進行標記,而不管dll如何,並使用目錄系統加載它們。 DirectoryCatalog文件夾有一個

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM