Type.GetType 在作为方法组调用但不在 lambda 表达式中调用时失败
本文关键字:调用 表达式 lambda 失败 方法 Type GetType | 更新日期: 2023-09-27 18:32:17
下面的示例演示 Type.GetType 在特定情况下失败。
当我在 lambda 表达式中向它提供类名字符串(包括命名空间)时,GetType 会成功,但当我将对 GetType 的调用指定为方法组时,它会失败。
失败:
collectionOfClassNames.Select(GetType)
成功:
collectionOfClassNames.Select(s => GetType(s))
当类路径包含程序集名称时,这两种方法都成功。我怀疑这与给定为上述内容生成的 IL 的当前上下文/范围有关。我可以看到IL的差异,但我仍然无法解释确切的原因。
下面是演示问题的可运行示例。
using System;
using System.Linq;
using System.Reflection;
namespace GetTypeTest
{
public class FindMe{}
class Program
{
static void Main(string[] args)
{
var assemblyName = Assembly.GetExecutingAssembly().FullName;
var className = "GetTypeTest.FindMe";
var classAndAssembly = string.Format("{0}, {1}", className, assemblyName);
// 1) GetType succeeds when input is "class, assembly", using method group
var result = new[] { classAndAssembly }.Select(Type.GetType).ToArray();
Console.WriteLine("1) Method group & class+assembly: {0}", result.First());
// 2) GetType fails when input is just the class name, using method group
var result2 = new[] { className }.Select(Type.GetType).ToArray();
Console.WriteLine("2) Method group & class name only: {0}", result2.First());
// 3) Identical to (2) except using lamba expression - this succeeds...
var result3 = new[] { className }.Select(s => Type.GetType(s)).ToArray();
Console.WriteLine("3) Lambda expression & class name only: {0}", result3.First());
// 4) Method group and core type class name
var result4 = new[] { "System.String" }.Select(Type.GetType).ToArray();
Console.WriteLine("4) Method group for System.String: {0}", result4.First());
Console.ReadLine();
}
}
}
我想知道为什么 #2 失败但 #3 成功。
我不是 100% 确定,我可能是错的。我会提出我所研究的内容。
版本 2 被编译成一个 func 委托,如下所示new Func<string, Type>(Type.GetType)
版本 3 被编译成同一类中的编译器生成方法,如下所示
[CompilerGenerated]
private static Type <Main>b__0(string s)
{
Type type;
type = Type.GetType(s);
Label_0009:
return type;
}
和功能new Func<string, Type>(Program.<Main>b__0)
因此,虽然执行枚举器版本2只是一个将调用func
但我WhereSelectArrayIterator<TSource, TResult>
私有类存在于System.Core中.dll
版本 3位于程序集中的位置。
说到点子上。如果使用部分名称(没有完全限定名称)调用 Type.GetType
,则它不知道类型驻留在哪个程序集,它获取调用assembly
并假定类型驻留在那里。
因此,Version3 存在于您的程序集中,Type.GetType
找出您类型的程序集并扫描程序集完全返回正确的类型。
但在版本 2 中并非如此。您实际上并没有在那里调用Type.GetType
。它正在由System.Core.dll
中的WhereSelectArrayIterator... class
调用。因此,这假设您的类型存在于System.Core.dll
并且Type.GetType
无法找到您的类型。
编辑:以下片段证明上述陈述是正确的
我们在程序集中伪造一个类并将其命名System.Linq.Expressions.Expression
以查看行为。
namespace GetTypeTest
{
public class FindMe { }
class Program
{
static void Main(string[] args)
{
var assemblyName = Assembly.GetExecutingAssembly().FullName;
var className = "System.Linq.Expressions.Expression";//"GetTypeTest.FindMe";
var classAndAssembly = string.Format("{0}, {1}", className, assemblyName);
// 1) GetType succeeds when input is "class, assembly", using method group
var result = new[] { classAndAssembly }.Select(Type.GetType).ToArray();
Console.WriteLine("1) Method group & class+assembly: {0}, {1}", result.First(), result.First().Assembly);//your assembly
// 2) GetType fails when input is just the class name, using method group
var result2 = new[] { className }.Select(Type.GetType).ToArray();
Console.WriteLine("2) Method group & class name only: {0}, {1}", result2.First(), result2.First().Assembly);//System.Core assembly
// 3) Identical to (2) except using lamba expression - this succeeds...
var result3 = new[] { className }.Select(s => Type.GetType(s)).ToArray();
Console.WriteLine("3) Lambda expression & class name only: {0}, {1}", result3.First(), result3.First().Assembly);//your assembly
// 4) Method group and core type class name
var result4 = new[] { "System.String" }.Select(Type.GetType).ToArray();
Console.WriteLine("4) Method group for System.String: {0}, {1}", result4.First(), result4.First().Assembly);//mscorlib assembly
Console.ReadLine();
}
}
}
namespace System.Linq.Expressions
{
public class Expression
{
}
}
输出
System.Linq.Expressions.Expression [your assembly]
System.Linq.Expressions.Expression [System.Core assembly] since WhereSelectArrayIterator.. belongs to System.Core assembly
System.Linq.Expressions.Expression [your assembly] since compiler generated method belongs to your assembly
System.Linq.Expressions.Expression [mscorlib assembly]
希望这有帮助