简体   繁体   English

如何将类序列化为属性?

[英]How to serialize class as attribute?

I am trying to serialize a class as an attribute. 我正在尝试将一个类序列化为一个属性。 Here's the use case: I need to store a large number of engineering parameters in an xml config file. 这是用例:我需要在xml配置文件中存储大量工程参数。 Scientific notation is involved, and it is required by the customer that the entered values remain in the exact form the user entered them. 涉及科学记数法,并且客户要求输入的值保持与用户输入它们的形式完全相同。 For example, if someone enters "5.3e-1" then it must remain like that, and cannot be converted into, say, "0.53". 例如,如果有人输入“ 5.3e-1”,则它必须保持原样,并且不能转换为“ 0.53”。 To this end I've created a Params class that stores both the entered string and double values (actually storing the double values is only for processing efficiency later). 为此,我创建了一个Params类,该类存储输入的字符串和双精度值(实际上存储双精度值只是为了以后的处理效率)。 Now here's the trick: I only want the string value to be serialized, and I want that to serialize as an attribute. 现在的诀窍是:我只希望将字符串值序列化,并且希望将其序列化为属性。

For example, if an object contains two parameters, A and B, where the string values are A.stringVal = "1.2e5" and B.stringVal = "2.0" then I would like: 例如,如果一个对象包含两个参数A和B,其中字符串值为A.stringVal =“ 1.2e5”和B.stringVal =“ 2.0”,那么我想:

public class MyObject
{
    [XmlAttribute]
    public MyParam A { get; set; }

    [XmlAttribute]
    public MyParam B { get; set; }

    ...more stuff...
}

to serialize to: 序列化为:

<myObject A="1.2e5" B="2.0">
    more stuff...
</myObject>

My question is very similar to one asked here . 我的问题和这里的问题非常相似。 Unlike him I am fine with implementing IXmlSerializable (and would prefer to), I just can't make it work. 与他不同,我可以实现IXmlSerializable(并且愿意),但我无法使其正常工作。 When I try to serialize it I get a cryptic exception saying, "There was error reflection type." 当我尝试对其进行序列化时,我得到一个神秘的异常,说:“存在错误反映类型。” What am I doing wrong? 我究竟做错了什么?

  public class MyParam : IXmlSerializable
  {
     string name;
     string stringVal;
     double doubleVal;

     public string Val
     {
        get
        {
           return stringVal;
        }
        set
        {
           stringVal = value;
           doubleVal = double.Parse(value);
        }
     }

     public double DoubleVal
     {
        get
        {
           return doubleVal;
        }
        set
        {
           doubleVal = value;
           stringVal = value.ToString();
        }
     }

     public MyParam(string name)
     {
        this.name = name;
        this.stringVal = string.Empty;
        this.doubleVal = double.NaN;
     }

     public System.Xml.Schema.XmlSchema GetSchema()
     {
        return null;
     }

     public void ReadXml(System.Xml.XmlReader reader)
     {
        throw new NotImplementedException();
     }

     public void WriteXml(System.Xml.XmlWriter writer)
     {
        writer.WriteAttributeString(name, stringVal);
     }
  }

After I've added the parameterless constructor, I got the following exception: The element 'A' type ConsoleApplication1.MyParam can not be serialized. XmlAttribute / XmlText can not be used to encode types that implement IXmlSerializable. 添加无参数构造函数后,出现以下异常: The element 'A' type ConsoleApplication1.MyParam can not be serialized. XmlAttribute / XmlText can not be used to encode types that implement IXmlSerializable. The element 'A' type ConsoleApplication1.MyParam can not be serialized. XmlAttribute / XmlText can not be used to encode types that implement IXmlSerializable.

After removing IXmlSerializable I got an exception XmlAttribute/XmlText cannot be used to encode complex types. 删除IXmlSerializable我得到一个XmlAttribute/XmlText cannot be used to encode complex types.异常, XmlAttribute/XmlText cannot be used to encode complex types. And found this answer 并找到了这个答案

and this . 还有这个

So, I think, it is better to find another way to serialize attributes. 因此,我认为最好找到另一种序列化属性的方法。

To get what you want you need to control the serialization on the container that holds the properties, not the property itself. 要获得所需的内容,需要控制保存属性的容器(而不是属性本身)的序列化。 You can still encapsulate the serialization code in the property however, see below. 您仍然可以在属性中封装序列化代码,请参见下文。

public class MyObject : IXmlSerializable
{
    public MyParam A { get; set; }

    public MyParam B { get; set; }

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        throw new NotImplementedException();
    }

    public void WriteXml(XmlWriter writer)
    {
        //Call each properties "WriteAttribute" call.
        A.WriteAttribute(writer);
        B.WriteAttribute(writer);
    }
}

public class MyParam
{
    string name;
    string stringVal;
    double doubleVal;

    public string Val
    {
        get
        {
            return stringVal;
        }
        set
        {
            stringVal = value;
            doubleVal = double.Parse(value);
        }
    }

    public double DoubleVal
    {
        get
        {
            return doubleVal;
        }
        set
        {
            doubleVal = value;
            stringVal = value.ToString();
        }
    }

    public MyParam(string name)
    {
        this.name = name;
        this.stringVal = string.Empty;
        this.doubleVal = double.NaN;
    }

    internal void WriteAttribute(XmlWriter writer)
    {
        writer.WriteAttributeString(name, stringVal);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var test = new MyObject()
        {
            A = new MyParam("A"),
            B = new MyParam("B"),
        };

        test.A.Val = "1.2e5";
        test.B.Val = "2.0";

        var ser = new XmlSerializer(typeof(MyObject));
        var sb = new StringBuilder();
        using (var stream = new StringWriter(sb))
        {
            ser.Serialize(stream, test);
        }

        Console.WriteLine(sb);
        Console.ReadLine();
    }
}

Outputs 输出

<?xml version="1.0" encoding="utf-16"?>
<MyObject A="1.2e5" B="2.0" />

If you don't need the name of the property in the property itself you can modify the code to the following. 如果您不需要属性本身中的属性名称,则可以将代码修改为以下内容。

public class MyObject : IXmlSerializable
{
    //....

    public void WriteXml(XmlWriter writer)
    {
        //Call each properties "WriteAttribute" call.
        A.WriteAttribute(writer, "A");
        B.WriteAttribute(writer, "B");
    }
}

public class MyParam
{
    //...

    public MyParam()
    {
        this.stringVal = string.Empty;
        this.doubleVal = double.NaN;
    }

    internal void WriteAttribute(XmlWriter writer, string name)
    {
        writer.WriteAttributeString(name, stringVal);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM