Методы расширения и реализация GetBytes - PullRequest
1 голос
/ 23 июня 2010

Я хотел бы использовать метод расширения GetBytes для класса List ...

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

При компиляции я получаю сообщение об ошибке компилятора, в котором говорится, что аргумент '1': невозможно преобразовать из 'Т 'до' двойной '.Может кто-нибудь объяснить мне, в чем проблема?

1 Ответ

6 голосов
/ 23 июня 2010

BitConverter не имеет реализации GetBytes , которая работает с произвольными типами. Вы должны передать аргумент правильного типа, такой как double, int и т. Д.

Компилятор не находит подходящую перегрузку и "устанавливает значение по умолчанию" для двойной перегрузки, а затем сообщает об этом как об ошибке компилятора.


Чтобы использовать это для общего типа, вам также необходимо передать Func, который преобразуется в байты. Это будет работать:

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

Затем вы можете использовать это как:

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

К сожалению, строка «BitConverter.GetBytes» (или какая-либо другая функция для этого преобразования) делает вызов API немного менее «симпатичным», но он работает правильно. Это может быть удалено для определенных типов T путем добавления перегрузок, таких как:

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

Редактировать: поскольку вам нужно избегать SelectMany, вы можете просто написать основную функцию так же, как вы делали это раньше. SelectMany просто делает это проще:

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();
    }
}
...