Десериализуйте Поток для Списка <T> или любой другой тип

Попытка десериализовать поток к List<T> (или любой другой тип), и перестал работать с ошибкой:

Аргументы типа для метода Foo.Deserialize<T>(System.IO.Stream) не может быть выведен из использования. Попытайтесь указать аргументы типа явно.

Это перестало работать:

public static T Deserialize<T>(this Stream stream)
{
    BinaryFormatter bin = new BinaryFormatter();
    return (T)bin.Deserialize(stream);
}

Но это работает:

public static List<MyClass.MyStruct> Deserialize(this Stream stream)
{
    BinaryFormatter bin = new BinaryFormatter();
    return (List<MyClass.MyStruct>)bin.Deserialize(stream);
}

или:

public static object Deserialize(this Stream stream)
{
    BinaryFormatter bin = new BinaryFormatter();
    return bin.Deserialize(stream);
}

Действительно ли возможно сделать это без кастинга, например. (List<MyStruct>)stream.Deserialize()?

Обновление:
Используя stream.Deserialize<List<MyClass.MyStruct>>() результаты по ошибке:

System.InvalidCastException: Unable to cast object of type 'System.RuntimeType'
to type 'System.Collections.Generic.List`1[MyClass+MyStruct]'.
at StreamExtensions.Deserialize[T](Stream stream)
at MyClass.RunSnippet()

Обновите 2 (демонстрационное консольное приложение) - выполненный однажды, чтобы создать файл, снова читать из него

using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;

public static class StreamExtensions
{
    public static Stream Serialize<T>(this T o) where T : new()
    {
        Stream stream = new MemoryStream();
        BinaryFormatter bin = new BinaryFormatter();
        bin.Serialize(stream, typeof(T));
        return stream;
    }

    public static T Deserialize<T>(this Stream stream) where T : new()
    {
        BinaryFormatter bin = new BinaryFormatter();
        return (T)bin.Deserialize(stream);
    }

    public static void WriteTo(this Stream source, Stream destination)
    {
        byte[] buffer = new byte[32768];
        source.Position = 0;
        if(source.Length < buffer.Length) buffer = new byte[source.Length];
        int read = 0;
        while ((read = source.Read(buffer, 0, buffer.Length)) != 0)
        {
            destination.Write(buffer, 0, read);
        }
    }
}


public class MyClass
{
    public struct MyStruct
    {
        public string StringData;
        public MyStruct(string stringData)
        {
            this.StringData = stringData;
        }
    }

    public static void Main()
    {
        // binary serialization
        string filename_bin = "mydata.bin";
        List<MyStruct> l;
        if(!File.Exists(filename_bin))
        {
            Console.WriteLine("Serializing to disk");
            l = new List<MyStruct>();
            l.Add(new MyStruct("Hello"));
            l.Add(new MyStruct("Goodbye"));
            using (Stream stream = File.Open(filename_bin, FileMode.Create))
            {
                Stream s = l.Serialize();
                s.WriteTo(stream);
            }
        }
        else
        {
            Console.WriteLine("Deserializing from disk");
            try
            {
                using (Stream stream = File.Open(filename_bin, FileMode.Open))
                {
                    l = stream.Deserialize<List<MyStruct>>();
                }
            }
            catch(Exception ex)
            {
                l = new List<MyStruct>();
                Console.WriteLine(ex.ToString());
            }
        }

        foreach(MyStruct s in l)
        {
            Console.WriteLine(
                string.Format("StringData: {0}",
                    s.StringData
                )
            );
        }

        Console.ReadLine();
    }
}
9
задан Max 18 February 2014 в 00:29
поделиться

3 ответа

Я предполагаю, что вы вызываете свой метод расширения следующим образом:

List<MyStruct> result = mystream.Deserialize();    

В этом случае компилятор не может определить T для Deserialize (он не смотрит на переменная, которой присваивается результат вызова метода).

Итак, вам нужно явно указать аргумент типа:

List<MyStruct> result = mystream.Deserialize<List<MyStruct>>();

Это работает:

public static class StreamExtensions
{
    public static void SerializeTo<T>(this T o, Stream stream)
    {
        new BinaryFormatter().Serialize(stream, o);  // serialize o not typeof(T)
    }

    public static T Deserialize<T>(this Stream stream)
    {
        return (T)new BinaryFormatter().Deserialize(stream);
    }
}

[Serializable]  // mark type as serializable
public struct MyStruct
{
    public string StringData;
    public MyStruct(string stringData)
    {
        this.StringData = stringData;
    }
}

public static void Main()
{
    MemoryStream stream = new MemoryStream();

    new List<MyStruct> { new MyStruct("Hello") }.SerializeTo(stream);

    stream.Position = 0;

    var mylist = stream.Deserialize<List<MyStruct>>();  // specify type argument
}
9
ответ дан 3 November 2019 в 00:58
поделиться

Вы можете использовать свой исходный универсальный метод, вам просто нужно явно указать универсальный тип, например итак ...

stream.Deserialize<List<MyClass.MyStruct>>();
1
ответ дан 3 November 2019 в 00:58
поделиться

Вы сериализуете Type списка, а не сам список. Должно быть так:

bin.Serialize(stream, o)

Также, вам придется пометить MyStruct как Serializable, чтобы он сериализовался правильно.

1
ответ дан 3 November 2019 в 00:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: