2010-08-31 48 views
11

Tôi đang cố gắng hiểu tại sao mã bên dưới không hoạt động như mong đợi; TypeDescriptor chỉ đơn giản là không chọn công cụ chuyển đổi tùy chỉnh từ các thuộc tính. Tôi chỉ có thể giả định rằng tôi đã mắc phải một sai lầm rõ ràng nhưng tôi không thể nhìn thấy nó.Tại sao TypeConverter này không hoạt động?

- chỉnh sửa - mã này dường như hoạt động khi tôi chạy nó trong bảng điều khiển, tôi thực sự gọi một trình chuyển đổi từ trong một ứng dụng phức tạp hơn và từ một không gian tên khác.

- chỉnh sửa - thay thế bất kỳ đề xuất nào về cách tôi có thể gỡ lỗi TypeDescriptor để tôi có thể xem những gì đang diễn ra và sau đó tôi có thể tự mình trả lời.

- chỉnh sửa - sự cố này gần như chắc chắn liên quan đến các phần nằm trong các hội đồng khác nhau.

- chỉnh sửa - Có vẻ như thao tác này không hoạt động do một số tính năng không hoạt động của các assembly tải - mã này đang chạy dưới một plugin như kiến ​​trúc.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Drawing; 
using System.ComponentModel; 

namespace MyTest 
{ 

    public class TestTester 
    { 
     public static void Main(string[] args) 
     { 
      object v = TypeDescriptor.GetConverter(typeof(MyTest.Test)).ConvertFromInvariantString("Test"); 
     } 
    } 

    public class TestConverter : TypeConverter 
    { 

     public override bool GetStandardValuesSupported(ITypeDescriptorContext context) 
     { 
      return false; 
     } 

     public override bool CanConvertFrom(ITypeDescriptorContext context, System.Type sourceType) 
     { 
      if (sourceType == typeof(string) || base.CanConvertFrom(context, sourceType)) 
      { 
       return true; 
      } 
      return base.CanConvertFrom(context, sourceType); 
     } 

     public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
     { 
      if (destinationType == typeof(Test) || base.CanConvertTo(destinationType)) 
      { 
       return true; 
      } 
      return base.CanConvertTo(context, destinationType); 
     } 

     public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) 
     { 
      if (value.GetType() == typeof(string)) 
      { 
       Test t = new Test(); 
       t.TestMember = value as string; 
       return t; 
      } 
      return base.ConvertFrom(context, culture, value); 
     } 

     public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) 
     { 
      if (destinationType == typeof(string) && value.GetType() == typeof(Test)) 
      { 
       return ((Test)value).TestMember; 
      } 
      return base.ConvertTo(context, culture, value, destinationType); 
     } 

    } 

    [TypeConverterAttribute(typeof(TestConverter))] 
    public struct Test 
    { 
     public string TestMember { get; set; } 
    } 
} 

Trả lời

1

Tôi đã thấy các trường hợp, nơi tôi không thể lấy thuộc tính trên các trường nội bộ từ các hội đồng khác. Bạn không chắc đó có phải là lỗi .NET hay không nếu nó đã được sửa.

Điều duy nhất tôi có thể làm là trong trường hợp phức tạp, bạn có thể không có quyền Reflection.

+0

Tôi nghĩ rằng nó rất có khả năng làm với nó đang được trong hội đồng khác nhau - Tôi đã chỉ cố gắng di chuyển bit xung quanh; khi tôi đã có một PropertyGrid đề cập đến các mục trong một hội đồng khác nó không còn có thể sử dụng TypeConverters et al của nó để hiển thị thuộc tính. Tôi sẽ ngạc nhiên nếu không có giải pháp cho điều này mặc dù. – cyborg

10

Tôi đã gặp sự cố này và giải pháp cho sự cố là đăng ký sự kiện AssemblyResolve của miền ứng dụng hiện tại và giải quyết việc lắp ráp theo cách thủ công.

Đây là một giải pháp tốt, nhưng có vẻ như nó hoạt động. Tôi không biết tại sao khung làm việc theo cách này. Bản thân tôi thực sự muốn tìm cách giải quyết vấn đề này ít hackish hơn.

public void DoMagic() 
{ 
    // NOTE: After this, you can use your typeconverter. 
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); 
} 

private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 
{ 
    AppDomain domain = (AppDomain)sender; 
    foreach (Assembly asm in domain.GetAssemblies()) 
    { 
     if (asm.FullName == args.Name) 
     { 
      return asm; 
     } 
    } 
    return null; 
} 
1

Đây là một chút trễ, nhưng vấn đề này xuất hiện khi tôi yêu cầu một TypeConverter cư trú trong một hội đồng khác không được tham chiếu trực tiếp bởi hội đồng thi hành.

0

Chúng tôi cũng đã quan sát hành vi này trong các hệ thống có thể cắm liên quan đến việc tải các cụm từ bên ngoài thư mục cơ sở ứng dụng.

Gốc của mọi điều ác là một lỗ hổng trong triển khai TypeDescriptorAttribute.

Thuộc tính có hai quá tải khởi tạo, một cho một đặc tả kiểu bản rõ (không phải là bất ngờ - ma thuật thuần túy khi chạy) và một cho tham chiếu typeof(). Nếu bạn sử dụng con đường thứ hai, những gì có thể có thể đi sai? Vâng, thực sự thuộc tính chỉ sử dụng đường dẫn đầu tiên. Tham chiếu kiểu thời gian chạy thực và chính xác được làm phẳng thành chữ thô, và ở đây có các con rồng. Vì vậy, nó không sử dụng viết một typeof() - nó luôn luôn là kịch bản rõ ràng và ma thuật bên trong.

Giải pháp? Không có lý tưởng, nhưng trong trường hợp của chúng tôi, chúng tôi chỉ sử dụng các loại chuyển đổi trong hệ thống của mình, vì vậy chúng tôi đã chọn ValueSerializerAttribute thay thế. Mà về cơ bản là cách của WPF để làm những thứ tương tự. Việc triển khai thực hiện đúng khoảng typeof().ctor quá tải ở chỗ nó thành công trong việc bảo tồn danh tính loại được ràng buộc sớm và luôn tải đúng loại, như được viết bằng mã.

Nếu bạn muốn mã hệ thống (hoặc WinForms) sử dụng trình chuyển đổi loại, điều này sẽ không hữu ích.

+0

Đã thử giải pháp của bạn và nó không hoạt động cho WPF. –

+0

Hãy chắc chắn rằng có một tài liệu tham khảo DLL từ DLL này đến một với loại đó - sau khi bạn biên dịch nó, không chỉ trong dự án. Hoặc biên dịch với một phiên bản trình biên dịch mới sử dụng Roslyn, nó không làm mờ các tham chiếu DLL như bản gốc. – hypersw

0

The answer to this other question sẽ được áp dụng tại đây. Đó là một giải pháp đơn giản hơn nhiều so với việc đăng ký AssemblyResolve.

Tóm lại, ý tưởng là đặt thuộc tính TypeConverter sử dụng tên chuỗi đầy đủ của loại trình chuyển đổi loại, thay vì sử dụng typeof để cung cấp tên lớp.

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