当T不可序列化时,如何序列化List<T>

4

案例:

在不同的应用程序域之间传递无法序列化的参数。

以下是我想要在远程域中调用的一些方法;

public RemoteClass
{
  public Test(Class1 obj);
  public Test(List<Class1> obj);
}

定义:

Class1    :   un-serializable

[Serializable]
Class2 : Class1  , ISerializable  //mark Class2 serializable
{
    //.....
}

以下是用于测试的代码:

using (MemoryStream s = new MemoryStream())
{
    BinaryFormatter f = new BinaryFormatter();
    f.Serialize(s, obj);
}

测试结果:

obj                                      result

Class1 obj=new Class1();                 exception

Class1 obj=new Class2();                 success

List<Class1> obj=new List<Class1);       exception  when obj contain some element;
obj.Add(new Class1();   

List<Class1> obj=new List<Class1);       exception  when obj contain some element; //how???
obj.Add(new Class2();

List<Class2> obj=new List<Class2);       success;
obj.Add(new Class2();   

Class1不是可序列化的类,我无法修改它,因此我定义了Class2,继承自Class1并实现ISerializable接口。当一个方法需要一个Class1的实例时,我可以传递Class2的实例来获得测试结果,这个解决方案很成功,但是对于List<Class1>却不起作用。


1
你能给我们一个类似于你的问题并且会导致问题的Class 1的例子吗?看起来你的问题应该是:“我怎样才能使这个类可序列化?” - Steve
Class1不可序列化,我无法修改它,因此我定义了Class2: Class1,Iserializable;现在Class2是可序列化的,当一个方法需要Class1时,我将传递Class2。 - Clover
8个回答

3

这就是为什么在“答案”中包含链接而不是实际解释总是一个坏主意的原因: “序列化代理”链接现在已经失效。如果我找到新链接,我会在这里发布它。 - Jazimov
它在archive.org上,我修复了链接。 - Anton Tykhyy

2

如何将 List<Class1> 实例转换为列表 List<Class2>(只要在 Class2 上声明适当的构造函数,以下内容应该有效):

// using System.Linq;
List<Class1> inputList = MyInputList();
List<Class2> outputList = inputList.ConvertAll<Class2>(a => new Class2(a));

你应该可以很好地序列化List<Class2>

你会发现,在你可以在任何接受List<Class1>的地方使用它之前,你需要将序列化的列表转换回List<Class> - 上面的变化反过来也同样适用。


是的,我可以将List<Class1>转换为List<Class2>,但远程类需要一个List<Class1>,而且我无法修改远程类。 - Clover
@Clover - 你应该定义第二个远程方法,接受一个 List<Class2> - 这个远程方法应该将列表转换回一个 List<Class1>,然后调用第一个远程方法。 - Justin

1

T 不可序列化时,无法序列化 List<T>


当我尝试序列化List<T>时,会抛出SerializationException异常,而当T不可序列化时,我可以序列化T。 - Clover

0

使用BinaryFormatter是不行的 - 除非基本类型是可序列化的,否则它不会让你这样做。不过,你可以将其序列化为 XML 并传递一个字符串或 byte[] - XmlSerializer 不那么挑剔:

using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using System;

public class Class1 { }
public class Class2 : Class1{}

static class Program {

    static void Main() {

        List<Class2> c2 = new List<Class2>();
        var ser = new XmlSerializer(typeof(List<Class1>), new[] {typeof(Class1), typeof(Class2)});

        List<Class1> objects = new List<Class1>(), clone;
        objects.Add(new Class2());
        objects.Add(new Class2());
        objects.Add(new Class2());
        using (var ms = new MemoryStream())
        {
            ser.Serialize(ms, objects);
            ms.Position = 0;
            clone = (List<Class1>)ser.Deserialize(ms);
        }
        Console.WriteLine(clone.Count);
    }
}

这里的区别显然在于XmlSerlializer发送公共成员,而不是字段。如果您想要二进制,我也知道我的序列化程序可以为您完成此操作。

0

当你将一个对象序列化时,所有的子对象也必须是可序列化的。

List<T> 是可序列化的,但仅在 T 也是可序列化的情况下才能对其进行序列化。我认为这个规则没有例外。

你有什么理由使 T 不可序列化呢?在大多数情况下,你只需要在类名上方添加 [Serializable] 就可以了!


T被定义在另一个组件中,我无法修改它。 - Clover

0

内置的BinaryFormatter不支持这种情况。如果您想要序列化没有标记为Serializable的类,则需要构建一个自定义序列化器,它不会检查Serializable属性。

当然,这将需要大量的工作。


是的,我定义了一个继承自Class1并实现ISerializable接口的Class2类,因此Class2是可序列化的,但List<Class1>仍然不可序列化,尽管其实际类型是Class2。 - Clover

0

如果您想要将其序列化为某种二进制格式,可以使用反射手动完成。虽然有些棘手,但可以完成,甚至比内置的二进制序列化更有效率。

如果您想要使用标准的 .Net 二进制序列化,除非您愿意在 T 上添加 [Serializable] 属性或者实现 T 的 ISerializable 接口,否则您将无法使用它。

如果您有兴趣手动编写序列化器,可以查看我在 Media Browser 中使用的一些代码。这取决于您想要支持的对象的复杂程度,因此不建议编写自己的序列化器,除非绝对必要。


0

如果内置的序列化程序无法满足您的需求,请尝试另一种选择:sharpserializer


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接