当作为方法组调用,但Type.GetType失败,不能在lambda EX pression能在、方法、Type、pression

2023-09-04 09:45:38 作者:累觉不爱

下面的例子显示Type.GetType没有在一个特定的场景。

The following example shows Type.GetType failing in a specific scenario.

的GetType成功时,我提供它的类名字符串(包括命名空间)在一个lambda EX pression,但失败时,我指定为方法组调用的GetType。

GetType succeeds when I provide it the class name string (including namespace) in a lambda expression, but fails when I specify the call to GetType as a method group.

失败:

collectionOfClassNames.Select(GetType)

成功:

collectionOfClassNames.Select(s => GetType(s))

这两种方法都在类路径包括集名称成功。我怀疑这件事情做与当前上下文/范围给出的IL生成以上。我可以看到在IL的差异,但我仍然无法解释具体原因。

Both methods succeed when the class path includes the assembly name. I suspect it's something to do with the current context/scope given the IL generated for the above. I can see the differences in the IL but I still can't explain the exact cause.

以下是一个可运行的例子,说明了问题。

The below is a runnable example that demonstrates the problem.

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成功。

I'd like to know why #2 fails but #3 succeeds.

推荐答案

我不是100%肯定,我可能是错的。。我会提出我所检验。

Am not 100% sure, I may be wrong.. I'll propose what I've examined.

2版被编译成FUNC委托像这样新的函数功能:LT;字符串类型>(Type.GetType)

Version 2 gets compiled into a func delegate like this new Func<string, Type>(Type.GetType)

3版被编译成一个编译器生成的方法,在你同一类这样的事情

Version 3 gets compiled into a compiler generated method in your same class something like this

[CompilerGenerated]
private static Type <Main>b__0(string s)
{
    Type type;
    type = Type.GetType(s);
Label_0009:
    return type;
}

和一个FUNC 新的函数功能:LT;字符串类型&GT;(计划&LT;主营&GT; b__0)

所以,在执行的枚举的版本2 的仅仅是一个 FUNC 将被调用我的 WhereSelectArrayIterator&LT; TSource,TResult&GT ; 私有类住在System.Core.dll的

So, While executing your enumerator Version2 is just a func which will be invoked my WhereSelectArrayIterator<TSource, TResult> private class lives in System.Core.dll

凡为的版本3 的住在您的程序集

来到点。如果 Type.GetType 与部分名称调用(不完全限定域名)不知道哪个组件类型所在,它就会调用组装并假设类型的生命存在。

Coming to the point. If Type.GetType is invoked with partial names(without fully qualified name) It doesn't knows which assembly the type resides, It gets the calling assembly and assumes the type lives there.

因此​​版本3 的生活在您的程序集 Type.GetType 想通了你的类型的组件与扫描组件完全返回正确的类型。

Hence Version3 lives in your assembly Type.GetType figured out your type's assembly and scans the assembly fully returns the correct type.

但是,这不是在版本2 的情况下。你不是真正调用 Type.GetType 有。它是由 WhereSelectArrayIterator ...类这是 System.Core.dll的调用。所以,这是假定你的类型的生命在 System.Core.dll的 Type.GetType 未能找出你的类型。

But this is not the case in Version2. You're not actually invoking the Type.GetType there. It is being invoked by WhereSelectArrayIterator... class which is in System.Core.dll. So this assumes your type lives in System.Core.dll and Type.GetType fails to find out your type.

编辑: 下面的代码片段证明上述声明是正确的。

Following snippet proves above statements were correct

我们假一类在我们的装配并将其命名为 System.Linq.Ex pressions.Ex pression 看到的行为。

We fake a class in our assembly and name it System.Linq.Expressions.Expression to see the behavior.

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]

希望这有助于

Hope this helps

 
精彩推荐
图片推荐