为什么此处Type.IsAssignableFrom方法返回false?

4
我遇到了一个使用.NET反射的奇怪问题。如果您知道为什么会发生这种情况,请告诉我。
要求:
我需要生成一个特定命名空间中实现特定接口的每个类的实例集合。
原始解决方案:
List<IReport> allReportTypes = Assembly.GetExecutingAssembly().GetTypes().Where(
    t => !t.IsAbstract && t.IsClass && t.IsAssignableFrom(typeof(IReport)) && t.Namespace
    == @namespace).Select(t => Activator.CreateInstance(t) as IReport).ToList();

这个原始解决方案没有返回任何内容,我的问题是为什么?每个类都正确实现了 IReport 接口,并在相应的命名空间中声明。这一点可以通过删除对 IsAssignableFrom 的调用来证明:
List<IReport> allReportTypes = Assembly.GetExecutingAssembly().GetTypes().Where(
    t => !t.IsAbstract && t.IsClass && t.Namespace == @namespace).Select(t => 
    Activator.CreateInstance(t) as IReport).ToList();

这将精确返回我想要的类的实例,但没有检查所需的接口。请注意,Activator.CreateInstance方法的结果成功地强制转换为IReport接口,因此返回的类绝对实现了它。我继续尝试解决这个问题,并成功地想出了以下查询的解决方案,满足了我所有的要求。

可行解决方案

List<IReport> allReportTypes = Assembly.GetExecutingAssembly().GetTypes().Where(
    t => !t.IsAbstract && t.IsClass && ((TypeInfo)(t)).ImplementedInterfaces.Contains(
    typeof(IReport)) && t.Namespace == @namespace).Select(t => Activator.CreateInstance(t)
    as IReport).ToList();

然而,我想知道为什么IsAssignableFrom方法没有像MSDN上说的那样起作用...(我也尝试了Stack Overflow上其他相关问题的已接受解决方案,但没有成功,请不要建议我跟随它们)。

1
请再次阅读说明书,我认为您把说明书倒过来了。 - Eric Lippert
@Maarten,请不要编辑我的代码,只是为了按照你喜欢的方式进行格式化。它现在已经非常清晰易读了。 - Sheridan
4
@Sheridan 你对“完全可读”的概念可能与几乎所有其他人的概念不同 :-) 但最终,这是你的代码。 - xanatos
哈哈,@EricLippert,谢谢...我确实把罐子倒过来了!这是一个多么棒的网站啊...在几秒钟内就得到了答案!!如此之快,以至于我甚至还没来得及接受答案!! - Sheridan
@Sheridan,非常抱歉,我只是想提高您的问题的可读性。我一直在努力理解您的LINQ语句的具体内容。 - Maarten
显示剩余2条评论
1个回答

6

This:

t.IsAssignableFrom(typeof(IReport))

有时候我们会犯错...例如:ReportClass是否可以从IReport继承?不可以!代码如下:

IReport someReport = ...;
ReportClass cl = someReport; // Error!

正确的做法是:

typeof(IReport).IsAssignableFrom(t)

一个`IReport`对象是否可以赋值给一个具体类型的`t`?
ReportClass cl = ...
IReport inter = cl; // OK :-)

啊,当然!这样更有意义!非常感谢。一旦可以,我会接受你的答案。 - Sheridan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接