在下面的代码片段中,最后一行的
Type.GetType
有时会返回null。
string assemblyName = "My.AssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
string typeName = "My.Namespaced.ClassName";
Type t1 = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(x => x.GetTypes())
.FirstOrDefault(x => x.FullName == typeName &&
x.Assembly.FullName == assemblyName);
string qualifiedName = t1.AssemblyQualifiedName; // this result looks sane
Type t2 = Type.GetType(qualifiedName); // returns null
如您所见,我使用的是
Type.AssemblyQualifiedName
返回的完全限定名称,并且正如预期的那样,qualifiedName
的值为 My.Namespaced.ClassName, My.AssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
。
在我的调用堆栈中的某个时刻,
Type.GetType
返回预期类型,但是,如果我们调用另一个程序集,完全相同的代码片段会导致t1
找到类型,但t2
为空。
这里任何地方都没有泛型,我从 @Eris 了解到,有时会导致 Type.AssemblyQualifiedName 为空值。 在这种情况下,AssemblyQualifiedName 是有效的。
我发现当人们没有使用程序集限定名称时,StackOverflow 上充斥着重复的问题,但这里的情况并非如此。
更新 我认为这个问题可以归结为以下问题:在什么情况下,如果我们有一个非空的
Type t
,其AssemblyQualifiedName
属性是typename和程序集的正确组合,Type.GetType(t.AssemblyQualifiedName);
可以返回null吗?
首先,我测试了您的往返,发现它确实可以正常工作。
你的代码和我的代码有什么区别?我不想手动输入完整的程序集名称,而是使用我反映的程序集获得了正确的名称,就我而言,
var assemblyName = Assembly.GetEntryAssembly().FullName;
显然,它给了我正确的名字。由于您和我的代码差异仅在第一行,因此我建议您手动输入的完整程序集名称是错误的。我的意思是,它可以是一个正确的名称,否则你不会获得
t1
,但不是你需要的名称。事实上,为什么你的 assemblyName
字符串值以 "My.AssemblyName"
开头,但你的 typeName
的命名空间是 "My.Namespaced"
?!在我的测试中,两个字符串都匹配。
结论:要解决您的问题,您需要检查代码前两行中的两个字符串。如果您输入正确的名称,其他一切都会起作用,我保证。
我想补充一些别的东西。使用基于常量或立即常量字符串值的反射在设计上是有缺陷的。它永远不可能变得可靠和可维护。名称可能在支持周期内发生变化,人们可能会拼写错误,人们可能会重命名名称空间并忘记这些字符串,等等。此外,我认为 .NET 标准不能保证严格固定的命名模式。毕竟,这严重违反了 S.P.O.T.原则(真理点)。
但是,我可以理解您这样做是为了研究或学习目的。在工作代码中,您需要使用可靠的方法,切勿在输入中使用字符串数据。为此,您必须遍历所有方法、所有属性或所有字段;在其他情况下,所有成员。只是为了这个想法:有时,您使用自定义属性标记您的成员,并搜索该属性是否存在。在其他情况下,您可能需要搜索实现某个接口的类,获取其实例,然后直接使用该接口,而不是反映单独的方法。在这些方法中,您永远不需要这些属性或接口的字符串表示形式。这种反思可以有不同的模式,我上面提到的只是举例,给你一些基本的想法。