2011-07-20 10 views
5

Quiero utilizar una función genérica WriteList (valor de lista) para escribir una lista usando BinaryWriter. Aquí está el código que estoy utilizando:¿Cómo escribo una lista usando BinaryWriter?

public void WriteList<T>(List<T> value) 
{ 
    for (int i = 0; i < value.Count; i++) 
    { 
     _writer.Write(value[i]); 
    } 
} 

El error que recibo es:

Error 1 The best overloaded method match for 'System.IO.BinaryWriter.Write(bool)' has some invalid arguments  
Error 2 Argument 1: cannot convert from 'T' to 'bool' 

El BinaryFormatter no es en absoluto una opción.

+3

alguna restricción en T? como T: struct? –

Respuesta

4

Si se echa un vistazo a los documentos de BinaryWriter que verá es imposible aceptar un argumento de objeto (Escribe tipos primitivos), y el compilador está haciendo todo lo posible a una sobrecarga, y en su defecto, ya que no puede lanza tu T a bool, o cualquier otra cosa que BinarwWriter desee.

Tendrás que convertir tu objeto en algo con lo que funcionará BinaryWriter.

+0

Tales como ... usar la reflexión para obtener todos los miembros del tipo de valor de la clase, y luego escribirlos uno tras otro con BinaryWriter. Sin embargo, considero que esto es parte de tu respuesta, ya que se trata del único lugar al que podrías acudir. – hoodaticus

+0

sí, pero quién querría. también podría encontrarse con problemas si tuviera un tipo de valor (struct) con un tipo de referencia como miembro. Si realmente deseaba hacer algo, podría implementar un serializador personalizado para que salga como byte [] o como cadena, etc., querría una buena razón real para hacer esto. – jasper

+0

en serio! La única buena razón que he encontrado es porque quieres un BinaryFormatter en Silverlight. – hoodaticus

5

Realmente no creo que puedas evitar BinaryFormatter. Porque el tipo T puede ser de cualquier tipo complejo y cada instancia de T puede representar un gran gráfico de variables en la memoria.

por lo que la única solución que tiene es convertir la instancia de T para el formato de byte [] y la solución más simple para esto es: BinaryFormatter

En realidad, la razón .Write() método sólo aceptará los tipos primitivos es que que sabe cómo convertir directamente a byte [] (usando Convert.ToXXX()) pero no hay forma en que podría adivinar que para el tipo genérico T.

como solución se puede definir un interfaz de la siguiente manera:

public interface IBinarySerializable 
{ 
    byte[] GetBytes(); 
} 

y luego implementar t en su clase:

public class MyClass: IBinarySerializable 
{ 
    public int X {get;set;} 
    public byte[] GetBytes() 
    { 
     return BitConverter.GetBytes(X); // and anyother 
    } 
} 

y cambiar su método para esto:

public void WriteList<T>(List<T> value) where T:IBinarySerializable 
{ 
    for (int i = 0; i < value.Count; i++) 
    { 
     _writer.Write(value[i].GetBytes()); 
    } 
} 
4

no se puede pasar un T genérico para BinaryWriter.Write - tiene sobrecargas para muchos tipos específicos (bool, byte, byte [], int, cadena, etc.), pero no genérico. Por lo tanto, tendrá que hacerlo usted mismo, de alguna manera similar al siguiente código.

public void WriteList<T>(List<T> value) 
    { 
     for (int i = 0; i < value.Count; i++) 
     { 
      switch (Type.GetTypeCode(typeof(T))){ 
      //_writer.Write(value[i]); 
       case TypeCode.Boolean: 
        _writer.Write((bool)(object)value[i]); 
        break; 
       case TypeCode.Byte: 
        _writer.Write((byte)(object)value[i]); 
        break; 
       case TypeCode.Char: 
        _writer.Write((char)(object)value[i]); 
        break; 
       case TypeCode.Decimal: 
        _writer.Write((decimal)(object)value[i]); 
        break; 
       case TypeCode.Double: 
        _writer.Write((double)(object)value[i]); 
        break; 
       case TypeCode.Single: 
        _writer.Write((float)(object)value[i]); 
        break; 
       case TypeCode.Int16: 
        _writer.Write((short)(object)value[i]); 
        break; 
       case TypeCode.Int32: 
        _writer.Write((int)(object)value[i]); 
        break; 
       case TypeCode.Int64: 
        _writer.Write((short)(object)value[i]); 
        break; 
       case TypeCode.String: 
        _writer.Write((string)(object)value[i]); 
        break; 
       case TypeCode.SByte: 
        _writer.Write((sbyte)(object)value[i]); 
        break; 
       case TypeCode.UInt16: 
        _writer.Write((ushort)(object)value[i]); 
        break; 
       case TypeCode.UInt32: 
        _writer.Write((uint)(object)value[i]); 
        break; 
       case TypeCode.UInt64: 
        _writer.Write((ulong)(object)value[i]); 
        break; 
       default: 
        if (typeof(T) == typeof(byte[])) 
        { 
         _writer.Write((byte[])(object)value[i]); 
        } 
        else if (typeof(T) == typeof(char[])) 
        { 
         _writer.Write((char[])(object)value[i]); 
        } 
        else 
        { 
         throw new ArgumentException("List type not supported"); 
        } 

        break; 
      } 
     } 
Cuestiones relacionadas