views:

49

answers:

1

I'd like to use a GetBytes extension method on the List class...

public static class Extensions
{
    public static byte[] GetBytes<T>(this ICollection<T> col)
    {
        List<byte> bytes = new List<byte>();
        foreach (T t in col)
            bytes.AddRange(BitConverter.GetBytes(t));

        return bytes.ToArray();
    }
}

When I compile, I am receiving a compiler error stating that Argument '1': cannot convert from 'T' to 'double'. Can anyone explain to me what the issue is?

+6  A: 

BitConverter doesn't have a GetBytes implementation that works on arbitrary types. You must pass an argument of the correct type, such as double, int, etc.

The compiler is not finding an appropriate overload, and "defaulting" to the double overload, then reporting it as a compiler error.


In order to use this on a general type, you'll need to also pass in a Func that converts to bytes. This would work:

public static class Extensions
{
    public static byte[] GetBytes<T>(this IEnumerable<T> col, Func<T, byte[]> conversion)
    {
        return col.SelectMany(conversion).ToArray();
    }
}

You could then use this like:

static void Main(string[] args)
{
    double[] test = new double[3]
                        {
                            0, 12, 14.12
                        };
    List<int> ilist = new List<int>() { 3,5,1 };

    byte[] doubles = test.GetBytes(BitConverter.GetBytes);
    byte[] ints = ilist.GetBytes(BitConverter.GetBytes);


    Console.WriteLine("Double collection as bytes:");
    foreach (var d in doubles)
    {
        Console.WriteLine(d);
    }

    Console.WriteLine("Int collection as bytes:");
    foreach (var i in ints)
    {
        Console.WriteLine(i);
    }           

    Console.ReadKey();
}

Unfortunately, the "BitConverter.GetBytes" line (or some other function to do this conversion) makes the API call a little less "pretty", but it does work correctly. This could be removed for specific types of T by adding overloads, such as:

public static class Extensions
{
    public static byte[] GetBytes(this IEnumerable<double> col)
    {
        return GetBytes<double>(col, BitConverter.GetBytes);
    }

    public static byte[] GetBytes(this IEnumerable<int> col)
    {
        return GetBytes<int>(col, BitConverter.GetBytes);
    }
    // Add others as needed

    public static byte[] GetBytes<T>(this IEnumerable<T> col, Func<T, byte[]> conversion)
    {
        return col.SelectMany(conversion).ToArray();
    }
}

Edit: Since you need to avoid SelectMany, you can just write the main function the same way you did previously. SelectMany just makes this simpler:

public static class Extensions
{
    public static byte[] GetBytes<T>(this IEnumerable<T> col, Func<T, byte[]> conversion)
    {
        List<byte> bytes = new List<byte>();
        foreach (T t in col)
            bytes.AddRange(conversion(t));

        return bytes.ToArray();
    }
}
Reed Copsey
Unfortunately I cannot use SelectMany since I am running on the .Net CF platform...sorry I should of mentioned this before. Any suggestions to replacing that?
dirtmike
@dirtmike: I just edited to show you - basically, just put in your original code, but sub. out the Func ;) It will work fine. Everything else applies as above.
Reed Copsey
I totally missed what the conversion generic was. Thanks a lot!
dirtmike