2010-09-21 31 views
17

Tôi đã gặp một hành vi lạ trong dự án .NET 4 (rất lớn) của tôi. Tại một số điểm trong các mã, tôi đề cập đến một loại đầy đủ, nói:Tại sao System.Type.GetType ("Xyz") trả về null nếu typeof (Xyz) tồn tại?

System.Type type = typeof (Foo.Bar.Xyz); 

sau này, tôi làm điều này:

System.Type type = System.Type.GetType ("Foo.Bar.Xyz"); 

và tôi nhận được lại null. Tôi không thể hiểu được lý do tại sao điều này xảy ra, bởi vì tên loại của tôi là chính xác, và tôi đã kiểm tra với các loại khác và chúng được giải quyết đúng cách. Hơn nữa, truy vấn LINQ sau đây tìm thấy loại:

var types = from assembly in System.AppDomain.CurrentDomain.GetAssemblies() 
      from assemblyType in assembly.GetTypes() 
      where assemblyType.FullName == typeName 
      select assemblyType; 

System.Type type = types.FirstOrDefault(); 

Có bất kỳ lý do nào tại sao System.Type.GetType có thể không thành công?

Tôi đã cuối cùng đã phải nhờ đến đoạn mã này thay vì GetType:

System.Type MyGetType(string typeName) 
{ 
    System.Type type = System.Type.GetType (typeName); 

    if (type == null) 
    { 
     var types = from assembly in System.AppDomain.CurrentDomain.GetAssemblies() 
        from assemblyType in assembly.GetTypes() 
        where assemblyType.FullName == typeName 
        select assemblyType; 

     type = types.FirstOrDefault(); 
    } 

    return type; 
} 

Trả lời

26

Nếu bạn chỉ đặt tên lớp (trong đó thì cần đủ điều kiện về không gian tên), Type.GetType(string) sẽ chỉ xem trong hội đồng hiện đang thi hành và mscorlib. Nếu bạn muốn nhận các kiểu từ bất kỳ assembly nào khác, bạn cần xác định tên đầy đủ bao gồm cả thông tin assembly. Như François nói, Type.AssemblyQualifiedName là một cách hay để thấy điều này. Dưới đây là một ví dụ:

using System; 
using System.Windows.Forms; 

class Test 
{ 
    static void Main() 
    { 
     string name = typeof(Form).AssemblyQualifiedName; 
     Console.WriteLine(name); 

     Type type = Type.GetType(name); 
     Console.WriteLine(type); 
    } 
} 

Output:

System.Windows.Forms.Form, System.Windows.Forms, Version = 4.0.0.0, Culture = trung tính,
PublicKeyToken = b77a5c561934e089
System.Windows.Forms.Form

Lưu ý rằng nếu bạn đang sử dụng cụm lắp ráp mạnh (như Form trong trường hợp này), bạn phải bao gồm tất cả các thông tin lắp ráp - versioning, token khóa công khai, vv

Nếu bạn đang sử dụng một tổ chức phi mạnh mẽ tên lắp ráp, nó dễ dàng hơn - một cái gì đó như:

Foo.Bar.Baz, MyCompany.MyAssembly 

cho một loại gọi là Baz trong không gian tên Foo.Bar, trong assembly MyCompany.MyAssembly. Lưu ý sự vắng mặt của ".dll" ở cuối - đó là một phần của tên tệp, nhưng không phải là tên lắp ráp.

Bạn cũng nên biết sự khác biệt giữa tên C# và tên CLR cho những thứ như lớp lồng nhau và Generics. Ví dụ: typeof(List<>.Enumerator) có tên là System.Collections.Generic.List`1+Enumerator[T]. Mặt generics là khó khăn để làm việc ra, nhưng bit loại lồng nhau là dễ dàng - nó chỉ được đại diện với một "+" thay vì "." bạn sẽ sử dụng trong C#.

+0

Cảm ơn bạn rất nhiều vì đã trả lời. Thật vậy, tất cả các loại khác tôi đã được giải quyết cho đến bây giờ hoặc là nằm trong cùng một hội đồng hoặc trong mscorlib, vì vậy tôi đã không bắt lỗi trước. –

+0

Cung cấp 'System.Type.GetType' với thông tin lắp ráp một phần hoạt động ngay cả khi lắp ráp có tên mạnh. Tôi đã kiểm tra 'System.Type.GetType (" Foo.Bar.Baz, MyCompany.MyAssembly ")' và nó hoạt động ngay cả khi 'MyCompany.Assembly' có một tên mạnh. –

+0

để tham khảo trong tương lai, nếu bạn muốn sử dụng backtick trong một mã nổi bật (và BẠN có lẽ sẽ;), sử dụng double backticks để bắt đầu và đóng báo giá :). Xem [tại đây] (http://meta.stackexchange.com/q/82718/237379). – Noctis

4

Theo như tôi biết GetType trông cho "XYZ" trong một assembly có tên là Foo.Bar.dll và tôi giả sử nó không tồn tại.

GetType dựa vào việc bạn chuyển đường dẫn chính xác đến Xyz trong hội đồng. Hội và không gian tên không nhất thiết phải liên quan.

Hãy thử System.Type type = System.Type.GetType(typeof(Foo.Bar.Xyz).AssemblyQualifiedName) và xem điều đó có hiệu quả không.

Lý do bạn tìm thấy nó với ví dụ LINQ của bạn là bạn đang sử dụng GetAssemblies để thu thập các hội đồng đã được tải vào ngữ cảnh thực thi hiện tại và do đó có chi tiết cần tìm tất cả các loại trong hội đồng.

4

Từ MSDN documentation (tôi nhấn mạnh):

Nếu typeName bao gồm các không gian tên nhưng không phải là tên lắp ráp, phương pháp này tìm kiếm chỉ gọi lắp ráp của đối tượng và Mscorlib.dll, theo thứ tự đó. Nếu typeName hoàn toàn đủ điều kiện với tên lắp ráp một phần hoặc toàn bộ, phương pháp này tìm kiếm trong hội đồng được chỉ định. Nếu lắp ráp có một tên mạnh, một tên lắp ráp hoàn chỉnh là bắt buộc.

1

Tôi chỉ cần stumbled khi một vấn đề tương tự và muốn để lại điều này ở đây

Trước hết bạn có thể chỉ định AssemblyName trong chuỗi

var type = System.Type.GetType("Foo.Bar.Xyz, Assembly.Name"); 

Tuy nhiên điều này chỉ làm việc cho hội mà không có một mạnh mẽ Tên. Giải thích đã có trong Simons answer If the assembly has a strong name, a complete assembly name is required.

Vấn đề của tôi là tôi phải giải quyết một số System.Dictionary<?,?> từ một chuỗi khi chạy. Đối với một Dictionary<int, string> điều này có thể dễ dàng nhưng những gì về một Dictionary<int, Image>?

này sẽ cho kết quả trong

var typeName = "System.Collections.Generic.Dictionary`2[System.Int32, [System.Drawing.Image, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a]]"; 

Nhưng tôi không muốn viết tên mạnh. Đặc biệt là bởi vì tôi không muốn bao gồm các phiên bản kể từ khi tôi đang lập kế hoạch để nhắm mục tiêu nhiều khung với mã của tôi.

Vì vậy, đây là giải pháp của tôi

privat statice void Main() 
    { 
     var typeName = "System.Collections.Generic.Dictionary`2[System.Int32, [System.Drawing.Image, System.Drawing]]"; 
     var type = Type.GetType(typeName, ResolveAssembly, ResolveType); 
    } 

    private static Assembly ResolveAssembly(AssemblyName assemblyName) 
    { 
     if (assemblyName.Name.Equals(assemblyName.FullName)) 
      return Assembly.LoadWithPartialName(assemblyName.Name); 
     return Assembly.Load(assemblyName); 
    } 

    private static Type ResolveType(Assembly assembly, string typeName, bool ignoreCase) 
    { 
     return assembly != null 
      ? assembly.GetType(typeName, false, ignoreCase) 
      : Type.GetType(typeName, false, ignoreCase); 
    } 

Type.GetType(...) có quá tải mà acceps một func để lắp ráp và gõ giải quyết mà gọn gàng. Assembly.LoadWithPartialName không được dùng nữa nhưng nếu nó bị loại bỏ trong tương lai, tôi có thể nghĩ về một sự thay thế (lặp lại tất cả các assembly trong AppDomain hiện tại và so sánh các tên từng phần).

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