2009-09-10 38 views
57

如何提供將我的課程轉換爲其他類型的支持?例如,如果我有自己的管理byte[]的實現,並且我想讓人們將我的課程投放到只返回私人成員的byte[],那麼我該怎麼做?如何爲我的課程提供自定義演員支持?

通常的做法是讓他們也把這個字符串轉換成字符串,或者我應該重寫ToString()(或兩者)?

回答

64

您需要覆蓋轉換運算符,使用implicitexplicit,具體取決於您希望用戶必須投射它還是希望它自動發生。通常,一個方向將始終有效,這就是您使用implicit的地方,而另一個方向有時可能會失敗,這就是您使用explicit的地方。

public static implicit operator byte[] (MyType x) 
{ 
    byte[] ba = // put code here to convert x into a byte[] 
    return ba; 
} 
- :

的語法是這樣的(>byte[]永遠是可行的MyType

public static implicit operator dbInt64(Byte x) 
{ 
    return new dbInt64(x); 
} 

public static explicit operator Int64(dbInt64 x) 
{ 
    if (!x.defined) 
     throw new DataValueNullException(); 
    return x.iVal; 
} 

對於你的榜樣,從您的自定義類型說

or

public static explicit operator MyType(byte[] x) 
{ 
    if (!CanConvert) 
     throw new DataValueNullException(); 

    // Factory to convert byte[] x into MyType 
    MyType mt = MyType.Factory(x); 
    return mt; 
} 
+1

謝謝,正是我期待的。 – esac

2

我寧願有一些方法可以做到這一點,而不是重載演員操作。

explicit and implicit c#但要注意,從例如,使用顯式的方法,如果你這樣做:

string name = "Test"; 
Role role = (Role) name; 

然後一切都很好;但是,如果你使用:

object name = "Test"; 
Role role = (Role) name; 

現在你會得到一個InvalidCastException因爲字符串不能轉換到角色,爲什麼,編譯器僅查找在根據自己的編譯型編譯時隱式/顯式轉換。在這種情況下,編譯器將名稱視爲對象而不是字符串,因此不使用Role的重載操作符。

+0

看看你鏈接到的例子,它似乎在每個演員陣容上創建對象的新實例。任何想法如何對類的當前成員進行get/set類型的操作? – esac

17

您可以使用explicitimplicit關鍵字在您的類上聲明轉換運算符。

作爲一般的經驗法則,當轉換不可能失敗時,應該只提供implicit轉換運算符。轉換可能失敗時使用explicit轉換運算符。

public class MyClass 
{ 
    private byte[] _bytes; 

    // change explicit to implicit depending on what you need 
    public static explicit operator MyClass(byte[] b) 
    { 
     MyClass m = new MyClass(); 
     m._bytes = b; 
     return m; 
    } 

    // change explicit to implicit depending on what you need 
    public static explicit operator byte[](MyClass m) 
    { 
     return m._bytes; 
    } 
} 

使用explicit意味着你的類的用戶將需要做一個明確的轉換:

byte[] foo = new byte[] { 1, 2, 3, 4, 5 }; 
// explicitly convert foo into an instance of MyClass... 
MyClass bar = (MyClass)foo; 
// explicitly convert bar into a new byte[] array... 
byte[] baz = (byte[])bar; 

使用implicit意味着你的類的用戶不需要進行顯式轉換,這一切透明地發生:

byte[] foo = new byte[] { 1, 2, 3, 4, 5 }; 
// imlpicitly convert foo into an instance of MyClass... 
MyClass bar = foo; 
// implicitly convert bar into a new byte[] array... 
byte[] baz = bar; 
2

對於自定義投射支持,您需要提供演員操作符(顯式或隱式)。 EncodedString類的以下示例是使用自定義編碼的字符串的簡單實現(如果必須處理巨大的字符串並遇到內存消耗問題,可能會很有用,因爲.Net字符串是Unicode - 每個字符需要2個字節的內存 - 和EncodedString每個字符可以佔用1個字節)。

EncodedString可以轉換爲byte []和System.String。 代碼中的註釋揭示了一些光線,並解釋了隱式轉換可能會導致危險的示例。

通常您首先需要非常好的理由來聲明任何轉換運算符,因爲。

更多資料請訪問MSDN

class Program 
{ 
    class EncodedString 
    { 
     readonly byte[] _data; 
     public readonly Encoding Encoding; 

     public EncodedString(byte[] data, Encoding encoding) 
     { 
      _data = data; 
      Encoding = encoding; 
     } 

     public static EncodedString FromString(string str, Encoding encoding) 
     { 
      return new EncodedString(encoding.GetBytes(str), encoding); 
     } 

     // Will make assumption about encoding - should be marked as explicit (in fact, I wouldn't recommend having this conversion at all!) 
     public static explicit operator EncodedString(byte[] data) 
     { 
      return new EncodedString(data, Encoding.Default); 
     } 

     // Enough information for conversion - can make it implicit 
     public static implicit operator byte[](EncodedString obj) 
     { 
      return obj._data; 
     } 

     // Strings in .Net are unicode so we make no assumptions here - implicit 
     public static implicit operator EncodedString(string text) 
     { 
      var encoding = Encoding.Unicode; 
      return new EncodedString(encoding.GetBytes(text), encoding); 
     } 

     // We have all the information for conversion here - implicit is OK 
     public static implicit operator string(EncodedString obj) 
     { 
      return obj.Encoding.GetString(obj._data); 
     } 
    } 

    static void Print(EncodedString format, params object[] args) 
    { 
     // Implicit conversion EncodedString --> string 
     Console.WriteLine(format, args); 
    } 

    static void Main(string[] args) 
    { 
     // Text containing russian letters - needs care with Encoding! 
     var text = "Привет, {0}!"; 

     // Implicit conversion string --> EncodedString 
     Print(text, "world"); 

     // Create EncodedString from System.String but use UTF8 which takes 1 byte per char for simple English text 
     var encodedStr = EncodedString.FromString(text, Encoding.UTF8); 
     var fileName = Path.GetTempFileName(); 

     // Implicit conversion EncodedString --> byte[] 
     File.WriteAllBytes(fileName, encodedStr); 

     // Explicit conversion byte[] --> EncodedString 
     // Prints *wrong* text because default encoding in conversion does not match actual encoding of the string 
     // That's the reason I don't recommend to have this conversion! 
     Print((EncodedString)File.ReadAllBytes(fileName), "StackOverflow.com"); 

     // Not a conversion at all. EncodingString is instantiated explicitly 
     // Prints *correct* text because encoding is specified explicitly 
     Print(new EncodedString(File.ReadAllBytes(fileName), Encoding.UTF8), "StackOverflow.com"); 

     Console.WriteLine("Press ENTER to finish"); 
     Console.ReadLine(); 
    } 
} 
相關問題