【问题标题】:Xml Deserialization and default valuesXml 反序列化和默认值
【发布时间】:2013-01-10 19:29:10
【问题描述】:

我有一个包含模板(默认值)和指定字段的非标准 XML。作为一个例子总是受欢迎的:

<MyClass>
   <ArrayOfSubClass>
      <SubClass>
         <Par1>1</Par1>
         <Par2>2</Par2>
         <Par3>3</Par3>
         <ArrayOfSpecific>
            <Specific>
               <Par1>11</Par1>
            </Specific>
         </ArrayOfSpecific>
      </SubClass>
   </ArrayOfSubClass>
</MyClass>

我想将这个类 MyClass 反序列化为一个对象。如您所见,MyClass 是类SubClass 的集合,它具有三个参数和类Specific 的集合。 SubClassSpecific 类派生自同一个母类。

什么 ISpecific 我希望找到默认值(即在SubClass 中找到的值),除非给出了一个字段。到目前为止,我所做的是实现一种方法,该方法通过反射检查 Specific 类的属性是否具有属性类型的默认值,如果是这种情况,则将其替换为 SubClass 的属性。它工作得很好,但我没有涵盖所有情况。例如,假设我在SubClass 中有一个双重属性Par1 的值,比如Par1 = 1.234,但我希望它现在是0。问题是0 是double 类型的默认值,所以用我的方法我会检索SubClass 中的属性值。

最好的办法是先反序列化MyClass 对象,然后将类Specific 的所有属性与SubClass 中相同属性的值一起放入,然后再次反序列化到这个现有的对象中,它只会改变XML 文件中给出的属性。

这很棘手,我可以想象我的问题不容易理解......

[编辑:]为了更容易理解,这是我想要反序列化后的结果

<MyClass>
   <ArrayOfSubClass>
      <SubClass>
         <Par1>1</Par1>
         <Par2>2</Par2>
         <Par3>3</Par3>
         <ArrayOfSpecific>
            <Specific>
               <Par1>11</Par1>
               <Par2>2</Par2>
               <Par3>3</Par3>
            </Specific>
         </ArrayOfSpecific>
      </SubClass>
   </ArrayOfSubClass>
</MyClass>

反序列化后通过反射完成,如果Specific的属性有默认值,则取类SubClass的值。棘手的情况如下

<MyClass>
   <ArrayOfSubClass>
      <SubClass>
         <Par1>1</Par1>
         <Par2>2</Par2>
         <Par3>3</Par3>
         <ArrayOfSpecific>
            <Specific>
               <Par1>0</Par1> <----- 0 is the default value of a double
            </Specific>
         </ArrayOfSpecific>
      </SubClass>
   </ArrayOfSubClass>
</MyClass>

目前的结果是

<MyClass>
   <ArrayOfSubClass>
      <SubClass>
         <Par1>1</Par1>
         <Par2>2</Par2>
         <Par3>3</Par3>
         <ArrayOfSpecific>
            <Specific>
               <Par1>1</Par1>   <---- as 0 is the default value of a double, this property is set to the value of the SubClass
               <Par2>2</Par2>
               <Par3>3</Par3>
            </Specific>
         </ArrayOfSpecific>
      </SubClass>
   </ArrayOfSubClass>
</MyClass>

但我想要

<MyClass>
   <ArrayOfSubClass>
      <SubClass>
         <Par1>1</Par1>
         <Par2>2</Par2>
         <Par3>3</Par3>
         <ArrayOfSpecific>
            <Specific>
               <Par1>0</Par1>
               <Par2>2</Par2>
               <Par3>3</Par3>
            </Specific>
         </ArrayOfSpecific>
      </SubClass>
   </ArrayOfSubClass>
</MyClass>

【问题讨论】:

  • 我在这句话中迷路了:@“问题是 0 是 double 类型的默认值,所以用我的方法我会检索子类中属性的值。” ,你是什么意思,为什么这是一个问题?如果您只是将此值设置为零会发生什么?
  • 你用什么语言做这个?该帖子标记为“c”,但由于您提到了类和反射,我猜它是别的东西。
  • @Ramy :反序列化后,如果属性具有默认值,我将 SubClass 的值复制到 Specific 中。 double 的默认值为 0。问题是当我在Specific 中找到值为 0 的属性时,我怎么知道它是真的 0 还是默认值??

标签: c# xml deserialization


【解决方案1】:

这里是用于序列化的 CodeProject 链接集合,可能会有所帮助:

虽然我不确定我是否理解您的问题,但您能否不让您的类可序列化,并在 MyClass 示例中为适当的值编码序列化?

【讨论】:

  • 我知道我的问题不清楚,但这是我能做的最好的:-(所有类都是可序列化的。
  • 您能解释一下您的类的层次结构吗?你说 SubClass 和 Specific 都继承同一个基类。实现一个接口会更可行吗?
  • 我不确定我是否理解为什么界面会更好?基类只是各种属性的容器。目前,我将尝试的解决方案是反序列化后,将类SubClass 的所有值放入类Specific,然后解析到XML 文件中以查看该属性是否存在于XML 中,如果它存在用文件中给定的值覆盖其值。
  • 我并没有指出接口更可行。我只是想了解当前的实现。也许如果您将这些类嵌套在 MyClass 中,您可以在 MyClass 中本地化变量以指导序列化?除了几个集合类之外,我还没有深入到序列化/反序列化,但在我看来,如果你以你描述的方式序列化对象,对象的反序列化将是不准确的表示的初始对象。希望您的解决方案适合您。
  • 感谢您的 cmets,但呈现的对象的反序列化非常准确。生成的类具有与 XML 完全相同的数据结构,但是,我不同意它的设计,但我被强加了结构,我必须找到一种方法在适当的类中反序列化它......无论如何 :-)
【解决方案2】:

好的,我找到了解决我的问题的解决方法。我分两步(实际上是三步)来做这件事。首先,我将 XML 反序列化到我的类中。其次,我将Specific 类的所有属性设置为我通过反射在SubClass 中找到的默认值,期望一个字段(Specific 类的 If)。第三,我将 XML 重新加载到 DataSet 中。在那里,我查看名为SpecificDataTable,对于我的类的所有属性,我查看是否有任何同名的列,如果单元格包含一个值,我将其放入我的类中。

嘘!!!! 不是很漂亮,但很有效。

     DataSet xmlDS = new DataSet();
     xmlDS.ReadXml(filename);
     GetSpecifiedValuesInDataSet(xmlDS);

     DataTable table = xmlDS.Tables["Specific"];

     foreach(ArrayOfSubClass array in this.Items)
     {
        foreach(SubClass sub in array)
        {
           foreach(Specific specific in sub)
           {
              Type specificType = specific.GetType();

              DataRow modelRow = null;
              foreach(DataRow row in table.Rows)
              {
                 if(row["Par1"].ToString().Equals(specific.Par1.ToString()))
                 {
                    modelRow = row;
                    break;
                 }
              }

              if(modelRow != null)
              {
                 foreach(PropertyInfo propSpecific in specificType.GetProperties())
                 {
                    string propertyName = propSpecific .Name;
                    foreach(DataColumn col in table.Columns)
                    {
                       if(col.ColumnName.Equals(propertyName))
                       {
                          if(!string.IsNullOrEmpty(modelRow[propertyName].ToString()))
                          {
                             object value = Convert.ChangeType(modelRow[propertyName], propSpecific.PropertyType);
                             propSpecific.SetValue(modelProd, value, null);
                          }
                       }
                    }
                 }
              }
           }
        }
     }

然后瞧

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-26
    • 2015-03-02
    • 2011-03-30
    • 1970-01-01
    相关资源
    最近更新 更多