2013-09-21 28 views
7

Ví dụ sau đây cho thấy Type.GetType thất bại trong một trường hợp cụ thể.Loại.GetType không thành công khi được gọi là nhóm phương thức nhưng không có trong biểu thức lambda

GetType thành công khi tôi cung cấp chuỗi tên lớp (bao gồm cả không gian tên) trong biểu thức lambda, nhưng không thành công khi tôi chỉ định lệnh gọi GetType làm nhóm phương thức.

Thất bại:

collectionOfClassNames.Select(GetType) 

Thành Công:

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

Cả hai phương pháp thành công khi đường dẫn lớp bao gồm tên lắp ráp. Tôi nghi ngờ đó là một cái gì đó để làm với bối cảnh hiện tại/phạm vi cho IL tạo ra cho ở trên. Tôi có thể thấy sự khác biệt trong IL nhưng tôi vẫn không thể giải thích nguyên nhân chính xác.

Dưới đây là ví dụ chạy được thể hiện sự cố.

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(); 
     } 
    } 
} 

Tôi muốn biết lý do tại sao # 2 thất bại nhưng # 3 thành công.

Trả lời

3

Không chắc chắn 100%, có thể tôi đã sai. . Tôi sẽ đề xuất những gì tôi đã kiểm tra.

Phiên bản 2 được biên soạn thành một đại biểu func như thế này new Func<string, Type>(Type.GetType)

Phiên bản 3 được biên dịch vào một trình biên dịch tạo ra phương pháp trong cùng một cái gì đó lớp học của bạn như thế này

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

và đến một func new Func<string, Type>(Program.<Main>b__0)

Vì vậy, khi thực hiện điều tra số Phiên bản2 chỉ là một số func sẽ được gọi WhereSelectArrayIterator<TSource, TResult> của tôi lớp tin cuộc sống trong System.Core.dll

Trong trường hợp như Version3cuộc sống trong lắp ráp của bạn.

Đến điểm. Nếu Type.GetType được gọi với một phần tên (không có tên đầy đủ) Nó không biết lắp ráp các loại cư trú, Nó được gọi assembly và giả định các loại cuộc sống ở đó.

Do đó Version3 sống trong hội đồng của bạn Type.GetType đã tìm ra lắp ráp loại của bạn và quét toàn bộ cấu hình trả về đúng loại.

Nhưng đây không phải là trường hợp trong Phiên bản2. Bạn không thực sự gọi số Type.GetType ở đó. Nó đang được gọi bởi WhereSelectArrayIterator... class là trong System.Core.dll. Vì vậy, điều này giả định rằng loại của bạn sống ở số System.Core.dllType.GetType không thể tìm ra loại của bạn.


Edit: đoạn sau chứng minh trên báo cáo là đúng

Chúng tôi giả một lớp trong lắp ráp và tên của chúng tôi nó System.Linq.Expressions.Expression để xem hành vi.

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 
    { 

    } 
} 

Đầu ra

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

+0

này nghe có vẻ đúng. Thường sử dụng ['Assembly.GetType (string)'] (http://msdn.microsoft.com/en-us/library/y0cd10tb.aspx) để thay thế. Ví dụ với 'var assem = typeof (Program) .Assembly;', không có vấn đề gì khi sử dụng 'stringColl.Select (assem.GetType)'. –

+0

@JeppeStigNielsen Yup, Đúng vậy, chúng tôi cần sử dụng tên đủ điều kiện. BTW báo cáo của tôi là chính xác. Cập nhật câu trả lời của tôi với bằng chứng :) –

+0

Sử dụng hội đồng gọi là đầu vào cho một phương pháp là thiết kế API ghê tởm trên một phần của BCL. – usr

Các vấn đề liên quan