【问题标题】:Deserialize Stream to List<T> or any other type将 Stream 反序列化为 List<T> 或任何其他类型
【发布时间】:2010-06-01 12:21:06
【问题描述】:

尝试将流反序列化为 List&lt;T&gt;(或任何其他类型)并失败并出现错误:

方法Foo.Deserialize&lt;T&gt;(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&lt;MyStruct&gt;)stream.Deserialize()?

更新:
使用stream.Deserialize&lt;List&lt;MyClass.MyStruct&gt;&gt;() 会导致错误:

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

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

【问题讨论】:

    标签: c# generics extension-methods


    【解决方案1】:

    我假设你是这样调用你的扩展方法的:

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

    在这种情况下,编译器无法为Deserialize 确定T(它不会查看方法调用结果分配给的变量)。

    所以你需要明确指定类型参数:

    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
    }
    

    【讨论】:

    • @Sam:您的 Serialize 方法中有一个错误。您正在序列化 typeof(T)(这是一个 RuntimeType)而不是对象 o
    • 有[Serializable],只是忘了把它放在示例中...错误是序列化而不是反序列化(没有想到,因为没有抛出异常)
    • @dtb:我的 BinaryFormatter 遇到了完全相同的问题,感谢您指出。由于 XmlSerializer 在构造函数中使用了 typeof() ,因此很容易忽略。
    • 哇,@dtb ...我遇到了同样的错误,我已经解决了 3 个小时,直到我终于阅读了您的 cmets 并找到了答案!
    【解决方案2】:

    你可以使用你原来的泛型方法,你只需要像这样显式地指定泛型类型...

    stream.Deserialize<List<MyClass.MyStruct>>();
    

    【讨论】:

      【解决方案3】:

      您正在序列化列表的类型,而不是实际的列表。应该是:

      bin.Serialize(stream, o)
      

      此外,您必须将 MyStruct 标记为 Serializable 才能正确序列化。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-09-09
        • 1970-01-01
        • 2011-09-28
        • 2013-11-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-30
        相关资源
        最近更新 更多