0

我遇到了我自己的类的 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时,我遇到空值异常 - Bothbase.Valuethis.Coefficientare null

有没有什么办法解决这一问题?

4

3 回答 3

2

似乎这里的很多问题都源于使用您的域模型进行序列化。现在,这可以工作,但如果您的域模型与序列化程序想要做的事情稍有偏差,它也会有很大的问题。

我强烈建议尝试添加数据的第二个并行表示,作为“DTO 模型” - 意思是:一组对象,其工作是表示数据以进行序列化。S 而不是具有计算和依赖关系的复杂属性,您只需:

public double SomeValue { get; set; }

等等。关键是简单并且代表数据,而不是您的系统规则。你序列化到/从这个模型 - 这不应该是简单的 - 你将它映射到/从你的域模型。转换运算符可能很有用,但简单的“ToDomainModel”/“FromDomainModel”方法也可以正常工作。同样,像 AutoMapper 这样的工具可能会有所帮助,但 15 行 DTO-to/from-Domain 代码也不会受到伤害。

这避免了以下问题:

  • 构造函数
  • 非公开成员
  • 分配顺序
  • 只读成员
  • 版本控制

以及一系列其他常见的序列化痛点。

于 2013-07-15T21:51:55.033 回答
0

Value getter 和 setter 的一个问题是,如果在反序列化 Value 时未加载 Coefficient,则会导致除以零错误。更糟糕的是,它可能不会中断,而是实际上针对不正确的值进行计算,因为 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;
         }
    }
于 2013-07-15T21:31:52.767 回答
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);
于 2013-07-15T21:24:07.010 回答