user4653488
user4653488

Reputation: 31

Serialize classes, that contain non serializable members

Is there a possibility to serialize classes, that contain non-serializable members?

Example: I have a class Instruction, which has two members:

public class Instruction
{
    public OpCode Op { get; set; }
    public object Operand { get; set; } 
}

The problem is, that the type of the member Op is in a 3rd party library and I can't make it serializable. I tried BinaryFormatter and ProtoBuf, but both failed without marking the Op-member.

Anyone knows a solution to serialize my object anyway?

Upvotes: 3

Views: 2810

Answers (3)

xanatos
xanatos

Reputation: 111840

You could:

public class Instruction
{
    public OpCode Op { get; set; }

    public string OpString
    {
        get
        {
            return Op.Name;
        }

        set
        {
            Op = (OpCode)typeof(OpCodes).GetField(value, BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase).GetValue(null);
        }
    }

    public object Operand { get; set; }
}

and disable serialization for Op. In this way you would serialize the Name of the op code (a string), and you would then be able to deserialize it.

With BinaryFormatter you could use the ISerializable interface and manually serialize:

[Serializable]
public class Instruction : ISerializable 
{
    public OpCode Op { get; set; }

    public object Operand { get; set; }

    public Instruction()
    {
    }

    public Instruction(SerializationInfo info, StreamingContext context)
    {
        Op = (OpCode)typeof(OpCodes).GetField(info.GetString("Op"), BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase).GetValue(null);
        Operand = info.GetValue("Operand", typeof(object));
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Op", Op.Name);
        info.AddValue("Operand", Operand);
    }
}

Example of use:

var ins1 = new Instruction { Op = OpCodes.Add, Operand = (short)5 };
var ins2 = new Instruction { Op = OpCodes.Sub, Operand = 5.0 };

byte[] bytes;

using (var ms = new MemoryStream())
{
    var bf = new BinaryFormatter();
    bf.Serialize(ms, ins1);
    bf.Serialize(ms, ins2);
    bytes = ms.ToArray();
}

Instruction ins3, ins4;

using (var ms = new MemoryStream(bytes))
{
    var bf = new BinaryFormatter();
    ins3 = (Instruction)bf.Deserialize(ms);
    ins4 = (Instruction)bf.Deserialize(ms);
}

If Operand can be something that isn't directly serializable, you can then create a surrogate of it inside the the GetObjectData.

Upvotes: 2

Prinshul Jain
Prinshul Jain

Reputation: 116

One way is to create a wrapper class over Opcode and use object of this wrapper class in Instruction class for serialisation and other purposes in your application. In this way, you can get rid of any limitations with third party library.

Upvotes: 2

Mark Segal
Mark Segal

Reputation: 5550

Obviously if a part of a class is not serializable, you can't serialize that part, but you can ignore it (and give some default, probably null value when deserializing).

You can use the [ProtoIgnore] attribute to mark the Op property if you are using ProtoBuf, or the [NonSerialized] attributes for BinaryFormatter.

Upvotes: 3

Related Questions