I have a class with a couple of members I want to serialise to store state.
However, I want to serialise from WITHIN the class itself, not via some external class feeding it to a formatter.
So in theory I want to do something like:
[DataContract]
class MyClass
{
[DataMember]
private MyCompoundClass _someCompoundField;
[DataMember]
private int _someOtherField;
private void SaveState()
{
using (Stream stream = GetStream())
{
DataContractSerializer serialiser = new DataContractSerializer(typeof(MyClass));
serialiser.WriteObject(stream, this);
}
}
private void LoadState()
{
using (Stream stream = GetStream())
{
DataContractSerializer serialiser = new DataContractSerializer(typeof(MyClass));
this = (MyClass)serialiser.ReadObject(stream);
}
}
}
Now obviously the line
this = (MyClass)serialiser.ReadObject(stream);
is nonsense, but you can see what I'm trying to do. I want to serialise the two fields of my class from within the class. (I am using the WCF ser开发者_运维问答ializer, but I assume this will be the same if I use XmlSerializer).
I tried to implement this properly by serialising each field myself like so:
private void SaveState()
{
using (Stream stream = GetStream())
{
//serialise field 1
DataContractSerializer serialiser = new DataContractSerializer(typeof(MyCompoundClass));
serialiser.WriteObject(stream, _someCompoundField);
//serialise field 2
serialiser = new DataContractSerializer(typeof(int));
serialiser.WriteObject(stream, _someOtherField);
}
}
Now this works as a save, but when I come to read the document back in it throws an exception since there are two root nodes in the XML file.
How do I create my "wrapper" node to wrap my fields. Or is there some other way I should be doing this?
Many thanks,
I haven't seen any built-in deserialisation methods which modify an existing object, rather than returning a new one. Your options as I see them are:
- Deserialise a new
MyClass
and copy the members over - Make
LoadState
static and have it return the deserialisedMyClass
- Use a different serialisation mechanism which can do what you want
you could at your LoadState do:
private void LoadState()
{
using (Stream stream = GetStream())
{
DataContractSerializer serialiser = new DataContractSerializer(typeof(MyClass));
MyClass deserialized = (MyClass)serialiser.ReadObject(stream);
this._someCompoundField = deserialized._someCompoundField;
this._someOtherField = deserialized._someOtherField;
}
}
Are you tied to a specific serializer? protobuf-net supports that use-case, for example:
[DataContract]
class MyClass
{
[DataMember(Order = 1)]
private MyCompoundClass _someCompoundField;
[DataMember(Order = 2)]
private int _someOtherField;
private void SaveState()
{
using (Stream stream = GetStream())
{
ProtoBuf.Serializer.Serialize(stream, this);
}
}
private void LoadState()
{
using (Stream stream = GetStream())
{
ProtoBuf.Serializer.Merge(stream, this);
}
}
}
Note the addition of Order = n
on the member-attributes; that is because protobuf uses numeric identifiers on fields/properties, and needs a way to choose them. You can also use the project-specific [ProtoContract]
/[ProtoMember(n)]
attributes, but it works with the WCF ones too (as shown).
(Merge
is also available on the non-generic 2.0 API - but you pass this
in as an argument to Deseroalize
instead)
Put your deserialization method in a static method:
class MyClass
{
public static MyClass LoadState()
{
// Deserialize, and return the new MyClass instance.
}
}
To serialize just some objects, annotate some fields to avoid serialization, or create a superclass or interface with just the fields in it you want to serialize.
精彩评论