C# IsAssignableFrom() 在应该返回 true 时返回 false

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/345413/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 23:59:31  来源:igfitidea点击:

IsAssignableFrom() returns false when it should return true

c#.netreflection

提问by bingles

I am working on a plugin system that loads .dll's contained in a specified folder. I am then using reflection to load the assemblies, iterate through the types they contain and identify any that implement my IPlugininterface.

我正在开发一个插件系统,该系统加载包含在指定文件夹中的 .dll。然后我使用反射来加载程序集,遍历它们包含的类型并识别任何实现我的IPlugin接口的类型。

I am checking this with code similar to the following:

我正在使用类似于以下的代码进行检查:

foreach(Type t in myTypes )
{
    if( typeof(IPlugin).IsAssignableFrom(t) )
    {
       ...
    }
}

For some reason IsAssignableFrom() keeps returning false when it should be returning true. I have tried replacing the tby explicitly giving it a type that should pass, and it works fine, but for some reason it isn't working with the types that are returned from the loaded assembly. To make things stranger, the code works fine on my co-worker's machine but not on mine.

出于某种原因,IsAssignableFrom() 在应该返回 true 时一直返回 false。我已经尝试t通过明确地给它一个应该通过的类型来替换它,它工作正常,但由于某种原因,它不适用于从加载的程序集返回的类型。更奇怪的是,代码在我同事的机器上运行良好,但在我的机器上运行良好。

Does anyone know of anything that might cause this sort of behavior?

有谁知道可能导致这种行为的任何事情?

Thanks

谢谢

采纳答案by Jb Evain

That typically happens when there's a mismatch between the assembly which contains the type IPlugin that the current assembly references, and the assembly which is referenced by the assembly containg the types you're iterating over.

当包含当前程序集引用的类型 IPlugin 的程序集与包含您正在迭代的类型的程序集引用的程序集之间存在不匹配时,通常会发生这种情况。

I suggest you print:

我建议你打印:

typeof (IPlugin).Module.FullyQualifiedName

and

foreach (var type in t.GetInterfaces ()) 
{    
    Console.WriteLine (type.Module.FullyQualifiedName)
}

To see where the mismatch is.

看看哪里不匹配。

回答by Lawrence Dol

I work in Java which has the same API method and I just can't get my mind to grok it when reading the code (for some reason); therefore, I always read it in reverse as, in your case, "t is assignable to IPlugin). So if C# has "is" as Jonathon suggests, I would always use it - when reflecting in Java "instanceof" does not work for Class objects, only instances of the object.

我在 Java 中工作,它具有相同的 API 方法,但在阅读代码时(出于某种原因)我无法理解它;因此,我总是反过来阅读它,因为在您的情况下,“t 可分配给 IPlugin”。因此,如果 C# 具有 Jonathon 建议的“is”,我将始终使用它 - 当在 Java 中反映“instanceof”不适用于类对象,只有对象的实例。

回答by Mark Jones

The name of the Type.IsAssignableFrom method is vague and confusing when applied to testing inheritance or detecting interface implementations. The following wrapper for these purposes would make a lot more sense:

当应用于测试继承或检测接口实现时,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);
    }

Then, one can have more understandable application code such as:

然后,可以有更易于理解的应用程序代码,例如:

    bool CanBeTreatedAs = typeof(SimpleChildClass).CanBeTreatedAsType(typeof(SimpleClass));
    CanBeTreatedAs = typeof(SimpleClass).CanBeTreatedAsType(typeof(IDisposable));

The advantage of this method instead of the 'is' keyword is that it can be used at run-time to test unknown, arbitrary Types, whereas the 'is' keyword (and a generic Type parameter) requires compile-time knowledge of specific Types.

这种方法代替 'is' 关键字的优点是它可以在运行时用于测试未知的任意类型,而 'is' 关键字(和通用类型参数)需要特定类型的编译时知识.

回答by Mark Jones

Sometimes it's an issue with the dynamic assembly referencing another assembly.

有时是动态程序集引用另一个程序集的问题。

One simple thing to do it to disable local copy on the assembly (in visual studio right click the reference and set copy local to false). This should make it easier to nail down the directory where the assembly lives.

做一件简单的事情来禁用程序集上的本地复制(在visual studio中右键单击引用并将复制本地设置为false)。这应该更容易确定程序集所在的目录。

You can also implement an assembly resolver in-case .NET doesn't know how to initalize the type.

您还可以实现程序集解析器,以防 .NET 不知道如何初始化类型。

        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler([Resolve Function]);

回答by kad81

Some other answers have mentioned the lack of clarity in the name of the IsAssignableFrommethod. I agree, and as a result was using it in the wrong way.

其他一些答案提到了IsAssignableFrom方法名称不够清晰。我同意,结果以错误的方式使用它。

Try a little experimenting with reversing the objectsin your code and see if it works. For example:

尝试一些反转代码中的对象的实验,看看它是否有效。例如:

Replace:

代替:

if (typeof(IPlugin).IsAssignableFrom(t))

with:

和:

if (t.IsAssignableFrom(typeof(IPlugin)))

By doing this I not only got it to work, but began to understand what this method actually does.

通过这样做,我不仅让它起作用,而且开始了解这种方法的实际作用。

回答by elm

I had same issue when interface was defined in a separate assembly to implementing type. Iterating and loading assemblies from root folder that contained dlls with classes AND dll with interface resulted in type mismatch as mentioned above.

在单独的程序集中定义接口以实现类型时,我遇到了同样的问题。从包含带有类的 dll 和带有接口的 dll 的根文件夹迭代和加载程序集会导致如上所述的类型不匹配。

One solution was to change LoadFrom()to LoadFile()The LoadFrommethod has some disadvantages and that is one of them:

一个解决办法是改变LoadFrom()LoadFile()LoadFrom方法有一些缺点,这是其中之一:

If an assembly with the same identity is already loaded, LoadFrom returns the loaded assembly even if a different path was specified.

如果已加载具有相同标识的程序集,则即使指定了不同的路径,LoadFrom 也会返回已加载的程序集。

Another way to overcome this is to place all dlls with types implementing interface into separate folder and not to copy referenced assembly (CopyLocal = False) so Assembly.LoadFromwill not load dll containing interface in memory.

解决此问题的另一种方法是将具有实现接口的类型的所有 dll 放入单独的文件夹中,而不是复制引用的程序集 ( CopyLocal = False),因此Assembly.LoadFrom不会在内存中加载包含接口的 dll。