7

次の例は、特定のシナリオで Type.GetType が失敗することを示しています。

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 が成功する理由を知りたいです。

4

1 に答える 1

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)

したがって、列挙子Version2funcを実行している間、呼び出されるのは私のWhereSelectArrayIterator<TSource, TResult>プライベート クラスであり、System.Core.dll に存在します。

Version3 がアセンブリに存在する場合。

ポイントに来ます。部分的な名前 (完全修飾名なし) で呼び出された場合Type.GetType、型が存在するアセンブリはわかりません。呼び出しを取得assemblyし、型がそこにあると想定します。

したがって、 Version3はアセンブリ内に存在Type.GetTypeし、型のアセンブリを特定し、アセンブリをスキャンして正しい型を完全に返します。

しかし、これはVersion2には当てはまりません。あなたは実際にType.GetTypeそこを呼び出していません。によって呼び出されてWhereSelectArrayIterator... classSystem.Core.dllます。したがって、これはあなたのタイプが住んでいて、あなたのタイプを見つけられない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]

お役に立てれば

于 2013-09-21T11:23:20.523 に答える