I serialize an XML file into an object using the built-in .NET functionality (XmlSerializer.Deserialize). After the object's fields have been set, I want to act on that data by calling additional code in the object's constructor. Unfortunately, stepping through the code reveals that the "additional" code is executed first before the s开发者_开发技巧erialization logic is executed. That makes the approach unfeasible, since there fields haven't been initialized yet and there's no data to act on.
Is there a known solution to this problem? Up to now, I've always called a second method that does this initialization of data, but it's clunky and prone to errors: it has to be called after each serialization (other programmers might not be aware of that), or I have to create another wrapper to load the object (and stuff starts spiraling).
If a constructor is being invoked, it will always be the first thing (note that some serializers skip the constructor; XmlSerializer
always runs a public parameterless constructor). As such, any logic will have to be in the properties etc.
What you are really describing here is "serialization callback" - i.e. a way of getting the serializer to run a method of yours before and/or after serialization and/or deserialization; some serializers support callbacks - however, XmlSerializer
does not.
The only option with XmlSerializer
is to implement IXmlSerializable
, but frankly that is a huge pain. If possible, I would suggest either:
- call a method manually, yourself, after deserialization
- or, switch serializer to one that supports callbacks
DataContractSerializer
supports callbacks and can do limited xml - not as fine-grained control as XmlSerializer
though (no attributes, in particular); protobuf-net supports callbacks if you want to switch to binary.
Assuming you haven't implemented IXmlSerializable
, the serializer follows this flow to deserialize:
- Instantiate your object
- Read the XML piece by piece
- Set properties on your object
The serializer can't access properties on the object before construction is complete, so there is no way to do what you want to do. Edit: Even if you skip the constructor (see comments on Marc's answer), you won't be able to call the constructor after you've set properties on the object, since you can't call the constructor without constructing a new object.
Maybe you should make this object a serialization-only object (effectively a DTO), and take that in the constructor for another class that actually implements your domain model logic. This will help you avoid the two-step initialization grossness.
What I've done in the past is to create a Deserialize method on the object that you're creating. This encapsulates all of the serialization logic in a single location with the ability to add custom code before and/or after the serialization occurs.
Something like this:
public partial class MyObject
{
public static MyObject Deserialize(string xmlInputFile)
{
MyObject myobject;
//INSERT CODE HERE THAT RUNS BEFORE DESERIALIZATION
using (StreamReader sr = new StreamReader(xmlInputFile))
{
XmlSerializer xs = new XmlSerializer(typeof (MyObject));
myobject = (MyObject) xs.Deserialize(sr);
sr.Close();
}
//INSERT CODE HERE THAT RUNS AFTER DESERIALIZATION
return myobject;
}
}
Deserializing an XML file into a new object is as simple as writing:
MyObject myobject = MyObject.Deserialize(PathToXMLFile);
精彩评论