2009-09-10 12 views
57

¿Cómo proporciono asistencia para enviar mi clase a otros tipos? Por ejemplo, si tengo mi propia implementación de administrar un byte[], y quiero que las personas emitan mi clase a byte[], que solo devolverá al miembro privado, ¿cómo lo haría?¿Cómo proporciono soporte personalizado para mi clase?

¿Es una práctica común dejarlos también convertir esto a una cadena, o debería simplemente anular ToString() (o ambos)?

Respuesta

64

Debería anular el operador de conversión, utilizando implicit o explicit dependiendo de si desea que los usuarios tengan que emitirlo o si desea que ocurra automágicamente. En general, una dirección siempre funcionará, ahí es donde usa implicit, y la otra dirección a veces puede fallar, ahí es donde usa explicit.

La sintaxis es la siguiente:

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

o

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

Para su ejemplo, dicen desde su medida Tipo (MyType ->byte[] siempre funcionará):

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

o

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

Gracias, exactamente lo que estaba buscando hacer. – esac

2

Prefiero tener algún método que lo haga en lugar de sobrecargar al operador de transmisión.

Ver explicit and implicit c# pero tenga en cuenta que a partir de ese ejemplo, utilizando el método explícito, si lo hace:

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

Entonces todo está bien; Sin embargo, si utiliza:

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

Ahora va a tener una InvalidCastException porque la cadena no se puede convertir en papel, por eso, el compilador sólo busca conversiones implícitas/explícitos en tiempo de compilación en base a su tipo compilado. En este caso, el compilador ve el nombre como un objeto en lugar de cadena, y por lo tanto no utiliza el operador sobrecargado de Role.

+0

Al observar el ejemplo al que se ha vinculado, parece crear una nueva instancia del objeto en cada conversión. ¿Alguna idea de cómo obtener/establecer el tipo de operaciones en un miembro actual de la clase? – esac

17

Puede declarar operadores de conversión en su clase utilizando las palabras clave explicit o implicit.

Como regla general, solo debe proporcionar operadores de conversión implicit cuando la conversión no pueda fallar. Use los operadores de conversión explicit cuando la conversión pueda fallar.

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

Usando explicit significa que los usuarios de su clase tendrán que hacer una conversión explícita:

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; 

Usando implicit significa que los usuarios de su clase no es necesario realizar una conversión explícita, todo sucede de forma transparente:

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

Para el soporte de conversión personalizada, debe proporcionar operadores de conversión (explícitos o implícitos). El siguiente ejemplo de clase EncodedString es una implementación simplista de cadena con codificación personalizada (puede ser útil si debe procesar cadenas enormes y problemas de consumo de memoria porque las cadenas .Net son Unicode, cada carácter ocupa 2 bytes de memoria) y EncodedString puede tomar 1 byte por char).

EncodedString se puede convertir en byte [] y System.String. Los comentarios en el código arrojan algo de luz y también explican un ejemplo cuando la conversión implícita puede ser peligrosa.

Por lo general, necesita una buena razón para declarar a los operadores de conversión en primer lugar porque.

Lectura adicional está disponible en 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(); 
    } 
} 
Cuestiones relacionadas