2017-03-31 106 views
1

我有一個泛型類,MyClass<T>,我希望能夠隱式轉換某種類型,例如,例如bool,到通用類型的特定版本,例如, MyClass<string>。看來我不能使用任何的以下內容:有沒有辦法在C#中爲特定版本的泛型類型定義隱式轉換運算符?

  • ,因爲 「使用泛型類型 'MyClass的< T>' 要求 '1' 類型的參數(S)」 失敗:

    public static implicit operator MyClass(bool value) { return new MyClass<string>(value.ToString()); }

  • 失敗,因爲「沒有限制的通用名是在這種情況下無效」,並因爲「用戶自定義的轉換必須轉換或從封閉類型」:

    public static implicit operator MyClass<>(bool value) { return new MyClass<string>(value.ToString()); }

  • 失敗,因爲「用戶定義的轉換必須轉換或從封閉類型」:

    public static implicit operator MyClass<string>(bool value) { return new MyClass<string>(value.ToString()); }

  • 失敗,因爲「無法隱式轉換類型‘MyClass的<字符串>’到「MyClass的< T> 「「:

    public static implicit operator MyClass<T>(bool value) { return new MyClass<string>(value.ToString()); }

有什麼辦法這個可以的政績ved,還是我只需要沒有它就生活(並且在任何地方都會顯式調用轉換方法)?

回答

2

不,你不能這樣做。 C#規範很明確,您的implicit運營商必須轉換爲或從其聲明的類型轉換。它必須是確切的轉換,並且由於聲明類型正好是MyClass<T>,所以轉換必須是或者來自該轉換。

參見例如Can i use a generic implicit or explicit operator? C#C# Implicit operator with generic

在縱容或認可的XY Problem的風險,這裏有幾個哈克替代品:

// Break generics by checking the type explicitly. Requires ugly casting 
// and intermediate boxing, though it's possible that with some run-time 
// use of Expressions, you could cache a delegate that would handle the 
// conversion without the boxing. It'd still be ugly though. 
class Class1<T> 
{ 
    public Class1(T t) { } 

    public static implicit operator Class1<T>(bool value) 
    { 
     if (typeof(T) == typeof(string)) 
     { 
      return (Class1<T>)(object)(Class1OfString)value; 
     } 

     throw new InvalidOperationException("Invalid type T"); 
    } 
} 

// Subclass the generic, and declare the conversion there. Of course, then 
// to use the conversion, you have to reference this type explicitly. Ugly. 
class Class1OfString : Class1<string> 
{ 
    public Class1OfString(string text) : base(text) { } 

    public static implicit operator Class1OfString(bool value) 
    { 
     return new Class1OfString(value.ToString()); 
    } 
} 

class A 
{ 
    public static void M() 
    { 
     // These all compile and execute fine 
     Class1OfString c1 = true; 
     Class1<string> c2 = (Class1OfString)true; 
     Class1<string> c3 = true; 
    } 
} 

有一些上面的主題變化,但他們都將涉及規避和特殊外殼的以某種方式鍵入。

值得指出的是,除了這裏處理泛型與特定難度之外,還有其他原因使用implicitThe documentation狀態右側頂部是一個應該使用implicit只有「如果轉換不能保證會導致數據丟失」和實現「不應該拋出異常」。在這兩種情況下,這是「,以便它們可以安全地使用,而不需要程序員的意識」。換句話說,implicit的本質就是它們被隱式調用,而程序員甚至不必考慮它。所以他們必須總是工作,上面的一些例子並不一定是這種情況(並且在一個例子中,您必須使用明確的語法,因此無論如何您都可以實現運算符爲explicit)。

這些選項都不理想。但坦率地說,最初的情況也不是。泛型類型必須在具體的基礎上處理具體類型是很奇怪的。它讓人質疑泛型是否真的應該是通用的。有可能你真的應該做更像上面的子類化的例子,只能進一步應用。即使用泛型類型來處理需要的任何基本行爲,但是將所有專業化分類放到知道類型參數T的子類中。

由於缺乏問題的細節,我不能提供更多的建議。但是基本要求不夠明確,如果只有問題包含了更廣泛的問題陳述和關於是什麼導致您實現實際目標的細節,則可能會提供更好和更適用的答案。

+0

在隱式運算符的文檔中,聲明他們不應該拋出(我認爲即使沒有文檔,也很清楚它有多糟糕:)) – Evk

+0

@Evk:是的,我同意這個建議。如果保證轉換不會導致數據丟失,文檔還說只使用'implicit'「_,這也是一個很好的建議。但是OP明確地(抱歉)要求'implicit'的幫助,並且當提供一個沒有支持轉換的'T'類型時,我沒有看到一個很好的替代方法來拋出異常。也就是說,我認爲值得在我的回答中提及這些問題,所以謝謝提醒。 –

+0

感謝您的回答,@Peter。我曾想過你提出的兩種可能性;但是,他們都不能滿足我的需求,因爲我不能真正使用它們。你是什​​麼意思「雖然有可能在一些運行時使用表達式的時候,你可以緩存一個能夠在沒有裝箱的情況下處理轉換的代理」? – Tom

相關問題