我遇到了我自己的类的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
。
有什么方法可以解决这个问题吗?
答案 0 :(得分:2)
这里似乎很多问题源于使用您的域模型进行序列化。现在,这个可以工作,但如果您的域模型与序列化程序想要做的事情稍微偏离甚至,那么它也会产生很大的问题。
我强烈建议尝试添加数据的第二个并行表示,作为“DTO模型” - 意思是:一组对象,其作用是表示序列化的数据。 S而不是具有计算和依赖性的复杂属性,您只需:
public double SomeValue { get; set; }
等。关键点在于它很简单并代表数据,而不是系统的规则。您可以序列化到此模型/从该模型序列化 - 这不应该很简单 - 并且您可以将其映射到域模型或从域模型映射。转换运算符可能很有用,但简单的“ToDomainModel”/“FromDomainModel”方法也可以正常工作。同样,像AutoMapper这样的工具可能会有所帮助,但15行DTO到/来自域代码也不会有任何损害。
这避免了以下问题:
序列化中的一系列其他常见痛点。
答案 1 :(得分:0)
您需要告诉序列化程序您的基础对象具有派生项。尝试:
[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);
答案 2 :(得分:0)
Value getter和setter的一个问题是,如果在反序列化Value时没有加载Coefficient,那么它将导致除以零的错误。更糟糕的是,它可能不会中断,而是实际上针对不正确的值进行计算,因为系数可能具有存储在其中的预反序列化值。以下将解决除零情况,并希望在系数加载第二时正确更新值。实际上,通常通过序列化非计算值然后在派生属性上使用[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;
}
}