开发者

how to serialize List<T> when T is not serializable

Case:

Pass a unserializable parameter cross AppDomain.

Following is some method which i want to call in remote domain;

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

Define:

Class1    :   un-serializable

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

Following code used to test:

using (MemoryStream s = new MemoryStream())
{
    BinaryFormatter 开发者_开发百科f = new BinaryFormatter();
    f.Serialize(s, obj);
}

Test result:

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 is not a serializable calss, and I cannot modify it, so I have define Class2 which inherits from Class1 and implements ISerializable. I can pass an instance of Class2 when a method needs a instance of Class1 in test result and this solution is successful, however for List<Class1> this does not work.


Try creating a serialization surrogate for List<Class1>.


How about converting the List<Class1> instance into a list List<Class2> (the following should work as long as you declare a suitable constructor on Class2):

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

You should then be able to serialise List<Class2> just fine.

You find that you need to convert your serialised list back into a List<Class> before you can use it anywhere that accepts a List<Class1> - a variation on the above should work just as well in reverse.


You cant serialize a List<T> when T is not serializable.


When you serialize an object, all child objects must also be serializable.

List<T> is serializable, but you can only serialize it if T is also serializable. I don't think there are any exceptions to this rule.

What reason do you have for T to not be serializable? In most cases all you nee to do is add [Serializable] above the class name and that's all you need to do!


The built in BinaryFormatter will not support this. If you want to serialize classes that are not marked as Serializable, then you need to build a custom serializer that does not check the Serializable attribute.

This of course would be a lot of work.


If by serialize you mean, convert it to a binary format of sorts. You can do this manually using reflection. It gets tricky but can be done, even more efficiently than the built in binary serialization.

If you would like to use the standard .Net binary serialization you are out of luck, unless you are willing to add the [Serializable] attribute to T or implement ISerializable on T.

If you are interested in hand coding a serializer you could look at some of the code I use for Media Browser. It gets tricky depending on how complex the objects you are you want to support. Would not recommend writing your own serializer unless it is absolutely necessary.


You can't to that with BinaryFormatter - it won't let you unless the base type(s) is(/are) serializable. You could, however, serialize to xml and just pass a string or byte[] - XmlSerializer is less particular:

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

The difference here obviously being that XmlSerlializer sends the public members, not the fields. I also know my own serializer could do this for you if you want binary.


If the buildIn Serializer is not capable of what you want, try an alternative: sharpserializer

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜