2009-09-10 43 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(); 
    } 
} 
相关问题