Попытка десериализовать поток к 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();
}
}
Я предполагаю, что вы вызываете свой метод расширения следующим образом:
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
}
Вы можете использовать свой исходный универсальный метод, вам просто нужно явно указать универсальный тип, например итак ...
stream.Deserialize<List<MyClass.MyStruct>>();
Вы сериализуете Type списка, а не сам список. Должно быть так:
bin.Serialize(stream, o)
Также, вам придется пометить MyStruct
как Serializable
, чтобы он сериализовался правильно.