2010-08-31 23 views
11

我想了解爲什麼下面的代碼不能按預期工作; TypeDescriptor根本就沒有從屬性中獲取自定義轉換器。我只能假設我犯了一個明顯的錯誤,但我看不到它。爲什麼這個TypeConverter不工作?

- 編輯 - 此代碼似乎工作時,我自己在控制檯中運行它,實際上我調用一個更復雜的應用程序和從一個不同的名稱空間內的轉換器。

- 編輯 - 或者我可以調試TypeDescriptor的任何建議,以便我可以看到發生了什麼,然後我可以自己回答。

- 編輯 - 這個問題幾乎肯定與不同的程序集中的碎片相關。

- 編輯 - 它看起來像不工作,因爲動態加載程序集的一些怪癖 - 這個代碼運行在像體系結構的插件下。

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

回答

1

我見過這種情況,我無法從其他程序集的內部字段拾取屬性。不知道這是一個.NET錯誤還是已經修復。

我唯一能做的就是在複雜場景中,您可能沒有反射權限。

+0

我認爲這是最有可能做它在不同的程序集 - 我剛剛嘗試移動位;當我有一個PropertyGrid引用另一個程序集中的項目時,它不能再使用它的TypeConverters等來顯示該屬性。如果沒有解決這個問題,我會很驚訝。 – cyborg 2010-09-01 11:30:59

10

我也有這個問題以及解決問題的方法是訂閱當前應用程序域的AssemblyResolve事件並手動解析程序集。

這遠遠不是一個好的解決方案,但它似乎工作。我不知道爲什麼框架的行爲如此。我自己真的很想找到解決這個問題的方法。

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

這是有點晚了,但這個問題出現時,我問駐留在未直接由可執行程序集引用其他程序集的類型轉換器。

0

我們也在可插入系統中觀察到這種行爲,涉及從appbase文件夾外部加載程序集。

萬惡之源是TypeDescriptorAttribute實施中的一個缺陷。

該屬性有兩個構造函數重載,一個用於明文類型規範(在運行時並非意外 - 純魔術),一個用於早期綁定的參考。如果您使用第二條路徑,可能會出現什麼問題?那麼,實際上該屬性只使用第一個路徑。真實且正確的運行時類型引用被平化爲明文,並且這裏有龍。所以編寫一個typeof()是沒有用的 - 它總是內在的明文和魔法場景。

解決方案?沒有理想的選擇,但在我們的情況下,我們僅在系統內使用類型轉換,因此我們選擇了ValueSerializerAttribute。這基本上是WPF做同樣事情的方式。它的實現在重載時是正確的,因爲它成功地保留了早期綁定類型標識並始終加載正確的類型,如代碼中所寫。

如果您希望系統(或WinForms)代碼使用類型轉換器,這將無濟於事。

+0

試過你的解決方案,它不適用於WPF。 – 2016-05-09 20:44:56

+0

確保從此DLL到該類型的DLL的引用 - 在編譯之後,不僅在項目中。或者使用一個新的使用Roslyn的編譯器進行編譯,它不會像最初的那樣虛幻出DLL引用。 – hypersw 2016-05-15 11:57:30

0

The answer to this other question應該在這裏適用。這是一個比訂閱AssemblyResolve簡單得多的解決方案。

總之,想法是使用類型轉換器類的完整字符串名稱來設置TypeConverter屬性,而不是使用typeof來提供類名稱。