将流反序列化为列表或任何其他类型

发布于 2024-09-03 21:40:29 字数 3888 浏览 6 评论 0 原文

尝试将流反序列化为 List (或任何其他类型),但失败并出现错误:

无法从用法中推断出方法 Foo.Deserialize(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)stream.Deserialize()

更新:
使用 stream.Deserialize>() 会导致错误:

System.InvalidCastException:无法转换“System.RuntimeType”类型的对象
输入“System.Collections.Generic.List`1[MyClass+MyStruct]”。
在 StreamExtensions.Deserialize[T](Stream 流)
在 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();
    }
}

Attempting to deserialize a stream to List<T> (or any other type) and am failing with the error:

The type arguments for method Foo.Deserialize<T>(System.IO.Stream) cannot be inferred from the usage. Try specifying the type arguments explicitly.

This fails:

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

But this works:

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

or:

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

Is it possible to do this without casting, e.g. (List<MyStruct>)stream.Deserialize()?

Update:
Using stream.Deserialize<List<MyClass.MyStruct>>() results in an error:

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 (sample console app) - run once to create the file, again to read from it

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

挽容 2024-09-10 21:40:29

我假设您像这样调用扩展方法:

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

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

因此,您需要显式指定类型参数:

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
}

I assume you're calling your extension method like this:

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

In this case, the compiler cannot determine the T for Deserialize (it doesn't look at the variable the method call result is assigned to).

So you need to specify the type argument explicitly:

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

This works:

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
}
南…巷孤猫 2024-09-10 21:40:29

您可以使用原始的泛型方法,只需明确指定泛型类型,如下所示......

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

You can use your original generic method, you just have to specify the generic type explicitly like so...

stream.Deserialize<List<MyClass.MyStruct>>();
我很OK 2024-09-10 21:40:29

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

bin.Serialize(stream, o)

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

You are serializing the Type of the list and not the actual list. It should be:

bin.Serialize(stream, o)

Also, you will have to mark MyStruct as Serializable for it to serialize it correctly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文