6

I want to use a generic WriteList(List value) function to write a List using the BinaryWriter. Here is the code I am using:

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

The error I am receiving is:

 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'   

The BinaryFormatter is absolutely not an option.

LunchMarble
  • 5,079
  • 9
  • 64
  • 94

3 Answers3

6

I really don't think you can avoid BinaryFormatter. Because type T can be any complex type and each instance of T can represent a huge graph of variables on memory.

so the only solution you have is to convert your instance of T to the byte[] format and the simplest solution for that is: BinaryFormatter

Actually the reason .Write() method only accept primitive types is that it knows how to convert them directly to byte[] (using Convert.ToXXX()) but there is no way it could guess that for generic type T.

As a work around you can define an interface like this:

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

and then implement it in your class:

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

and change your method to this:

public void WriteList<T>(List<T> value) where T:IBinarySerializable
{
    for (int i = 0; i < value.Count; i++)
    {
        _writer.Write(value[i].GetBytes());
    }
}
Mo Valipour
  • 13,286
  • 12
  • 61
  • 87
4

If you check out the docs for BinaryWriter you'll see it doesnt accept an argument of object (Writes primitive types), and the compiler is trying its best at an overload, and failing, since you can't cast your T to bool, or anything else that BinarwWriter would like.

You're going to have to convert your object into something the BinaryWriter will work with.

jasper
  • 3,424
  • 1
  • 25
  • 46
  • Such as... using reflection to get all the value-type members of the class, and then writing them one after another with BinaryWriter. I consider this a part of your answer though, since it's about the only place you could go with it. – hoodaticus Jul 20 '11 at 22:35
  • yea, but who'd want to. you could also run into issues if you had a value type(struct) with a reference type as a member. If you really wanted to do something, you could implement a custom serializer to output as byte[] or string etc. would want a real good reason to do this imo. – jasper Jul 20 '11 at 22:44
  • Seriously! The only good reason I've ever found is because you want a BinaryFormatter in Silverlight. – hoodaticus Jul 20 '11 at 23:04
4

You can't pass a generic T to BinaryWriter.Write - it has overloads for many specific types (bool, byte, byte[], int, string, etc), but no generic one. So you'll need to do it yourself, in some way similar to the code below.

    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;
            }
        }
carlosfigueira
  • 85,035
  • 14
  • 131
  • 171