我正在与我自己的类的Xml序列化的问题。 这是一个派生类,不自然有一个参数的构造函数 - 我不得不添加一个只为序列化的缘故。 当然,因为我快成一种依赖/顺序问题。
下面是一个简化的,我希望还是能说明问题(我保留,以增加说明如果事实证明我并没有抓住问题的权利 - 我只是不想转储一个复杂的对象模型对你:))
public class Base{
public virtual Vector Value{ get; set;}
}
public class Derived : Base{
public Vector Coefficient { get; set; }
public override Vector Value{
get { return base.Value * Coefficient; }
set { base.Value = value / Coefficient; }
}
}
编辑 :为了避免混淆,我取代的值类型double
原始柱与未示出的,这里Vector
类型
当XmlSerializer的反序列化Derived
,我碰上空值例外-无论base.Value
和this.Coefficient
是null
。
有没有什么办法解决这一问题?
看来,这里的许多问题,从使用您的域模型系列化干。 现在,这可以工作,但它也可以是巨大的问题,如果您的域模型从串行想要做什么甚至略有偏差。
我强烈建议尝试添加该数据的第二平行表示,作为“DTO模式” - 意思是:一组对象,他们的工作就是代表了序列化的数据。 s,而不是使用计算和依赖复杂的属性,你只需要:
public double SomeValue { get; set; }
等关键的一点是这是很简单,代表了数据 ,而不是系统的规则。 您序列化到/从这个模型 - 这不应该是简单的 - 你从你的域模型映射这/。 转换运算符是有用的,但一个简单的“ToDomainModel” /“FromDomainModel”法正常工作了。 同样,像AutoMapper工具可以帮助,但DTO到/从域代码15行是不会伤害任何。
这避免了与问题:
和一系列的系列化等常见的痛点。
与你的价值getter和setter的一个问题是,如果系数不以反序列化的值时,时加载,那么它将被零次失误造成的鸿沟。 更糟的是,它可能不破,而是真正做到了对计算不正确的值,因为系数可能有存储在它的反序列化预值。 下面将通过零状况解决鸿沟,希望第二正确更新值,如果系数载荷。 事实上,这些情况下通常处理由串行化非计算的值,然后所导出的属性使用[XmlIgnoreAttribute]更好。
public class Derived : Base{
public override double Value{
get { return _coefficient; }
set {
if(Coefficient == 0){
base.Value = value;
}else{
base.Value = value / Coefficient;
}
}
private double _coefficient;
public double Coefficient{
get { return _coefficient; }
set {
if(Coefficient == 0)
{
temp = base.Value;
_coefficient = value;
Value = temp;
}
else{
_coefficient = value;
}
}
}
// Example by serializing unmodified value
public double Coefficient { get; set; }
public double BaseValue { get; set; }
[XmlIgnoreAttribute]
public double Value
{
get { return BaseValue * Coefficient; }
set
{
if(Coefficient != 0){
BaseValue = value / Coefficient;
}else{
BaseValue = value;
}
}
你需要告诉你的基础对象导出项目序列化。 尝试:
[XmlInclude(typeof(Derived))]
public class Base {
另外,您也可以在运行时解释:
public XmlSerializer(Type type, Type[] extraTypes){..}
在你的情况: new XmlSerializer(typeof(Base), new Type[] { typeof(Derived), ..});
而为了让事情变得更加通用的,如果有一个巨大的层次结构,你可以使用反射来获取的派生类型的列表:
// You'll want to cache this result, and it could be a lot of work to run this
// multiple times if you have lots of classes
var knownTypes = Assembly.GetExecutingAssembly().GetTypes().Where(
t => typeof(Base).IsAssignableFrom(t)).ToArray();
var serializer = new XmlSerializer(typeof(Base), knownTypes);