我使用内置的.NET功能(XmlSerializer.Deserialize)将XML文件序列化为对象。在设置了对象的字段之后,我想通过在对象的构造函数中调用其他代码来对该数据进行操作。不幸的是,单步执行代码表明在执行序列化逻辑之前首先执行“附加”代码。这使得这种方法不可行,因为那里的领域还没有初始化,也没有数据可以采取行动。
这个问题有解决方案吗?到目前为止,我总是调用第二种方法进行数据初始化,但它很笨拙且容易出错:必须在每次序列化后调用(其他程序员可能不知道),或者我必须创建另一个包装器来加载对象(并且东西开始呈螺旋状)。
答案 0 :(得分:4)
如果正在调用构造函数,它将始终是第一个事物(请注意,某些序列化程序会跳过构造函数; XmlSerializer
始终运行公共无参数构造函数)。因此,任何逻辑都必须在属性等中。
你 在这里描述的是“序列化回调” - 即一种让序列化程序在序列化和/或反序列化之前和/或之后运行你的方法的方法;某些序列化程序支持回调 - 但是,XmlSerializer
不支持。
XmlSerializer
的唯一选择是实施IXmlSerializable
,但坦率地说,这是一个巨大的痛苦。如果可能的话,我建议:
DataContractSerializer
支持回调并且可以执行受限 xml - 不像XmlSerializer
那样细粒度控制(特别是没有属性) ;如果要切换到二进制文件,protobuf-net支持回调。
答案 1 :(得分:1)
假设您尚未实现IXmlSerializable
,序列化程序将遵循此流程进行反序列化:
序列化程序在构造完成之前无法访问对象的属性,因此无法执行您想要执行的操作。 编辑:即使你跳过了构造函数(参见Marc答案的评论),你也无法在对象上设置属性后调用构造函数,因为你无法调用没有构造新对象的构造函数。
也许你应该让这个对象成为一个仅限序列化的对象(有效a DTO),然后在另一个实际实现域模型逻辑的类的构造函数中使用它。这将帮助您避免两步初始化粗略。
答案 2 :(得分:0)
我过去所做的是在您正在创建的对象上创建Deserialize方法。这将所有序列化逻辑封装在一个位置,并能够在序列化发生之前和/或之后添加自定义代码。
这样的事情:
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;
}
}
将XML文件反序列化为新对象就像编写:
一样简单 MyObject myobject = MyObject.Deserialize(PathToXMLFile);