【问题标题】:C# XMLSerializer and sequence of attribute serializationC# XMLSerializer 和属性序列化序列
【发布时间】:2014-11-20 08:49:27
【问题描述】:

我遇到了 XML 反序列化的问题。好吧,假设我的类具有三个属性:

public class Order
{
    private string name;
    [XmlAttribute("Name")]
    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            if (name != value)
            {
                name = value;
            }
        }
    }

    private string tid;
    [XmlAttribute("TID")]
    public string TID
    {
        get
        {
            return tid;
        }
        set
        {
            if (tid != value)
            {
                tid = value;
            }
        }
    }


    private Command command;
    [XmlAttribute("Command")]
    public string Command
    {
        get
        {
            return command.Name;
        }
        set
        {
            command = new Command(TID, Name, value);
        }
    }

    public Order()
    {

    }
}

如您所见,我需要在反序列化 Command 属性上创建一个带有参数构造函数的对象 Command - 但我需要 TID 和 Name 属性。我需要确保这些字段不为空。正如我所观察到的,XmlSerializer 正在根据用户编写属性的顺序反序列化属性。例如:

<Order Command="SetPlus" TID="W403" Name="SomeName" />

在这种情况下,第一个序列化的将是 Command 属性。但我还没有 TID 和 Name 属性!我不能相信用户会以正确的顺序传递属性,例如:

<Order TID="W403" Name="SomeName" Command="SetPlus" />

好吧,我需要一些事件或可以在反序列化完成时调用的东西,或者我需要确保 XmlSerializer 将按我想要的顺序反序列化属性。我唯一发现的是:

[XmlElement(Order = 1)]

[XmlElementAttribute(Order = 1)]

但它不适用于 XmlAttribute。

有办法做到这一点吗?希望我清楚地解释了我的问题。

【问题讨论】:

  • 您是否对所有公共成员使用 Order 属性?

标签: c# xml deserialization


【解决方案1】:

如果你的Command 只依赖于TIDName,你为什么还要序列化呢? 这只是多余的信息。

您应该在Command 属性上使用[XmlIgnore] 属性。 之后,您可以为您的Command 属性实现一种延迟加载方法。

顺便说一句:无论如何,您的代码都是错误的。在 Command 属性的 set 部分,您甚至不使用用户传入的值。 如果你这样做会更好:

private Command command;
[XmlIgnore]
public string Command
{
    get
    {
      if (command == null)
      {
        command = new Command(TID, Name));
      }
      return command.Name;
    }
}

编辑:

好的,在您更改帖子并实际使用 Command 属性设置器的值后,解决方案有点棘手,有多种方法。

我可能会做什么:

  • 将另一个名为CommandName 的属性添加到您的类中,这只是一个简单的字符串属性(带有getter),同时将XmlAttribute 添加到此属性中
  • [XmlIgnore] 添加到您的Command 属性,并从上面获取我的代码(延迟初始化),使用新的CommandName 属性返回命令(new Command(TID, Name, CommandName)

就我个人而言,我什至会在CommandName 属性中添加一个setter,让Command 属性实际上返回Command 而不是string。在我看来,这将使代码更清晰,更具可读性。

为了澄清,这就是我的班级的样子:

public class Order
{
    //todo: if Name, TID or CommandName changes you'd have to initialize a new Command objects with the new values

    [XmlAttribute("Name")]
    public string Name {get;set;}

    [XmlAttribute("TID")]
    public string TID {get;set;}

    [XmlAttribute("CommandName")]
    public string CommandName {get;set;}

    private Command command;
    [XmlIgnore]
    public Command Command
    {
      get
      {
        return command ?? (command = new Command(TID, Name, CommandName));
      }
    }
    public Order()
    {

    }
}

【讨论】:

  • 既然如此,为什么它还有一个setter?
  • 我猜他说的是反序列化而不是序列化。
  • 问题比较复杂。我给你一个非常简单的例子来理解它,忘记添加'value',像这样:command = new Command(TID, Name, value);
  • 刚刚意识到 setter 的“错误”,我用一个(在我看来)正确的例子更新了我的答案。
  • 当然我使用的是值,我只是忘记将它作为参数添加到构造函数中。我的错,对不起。
【解决方案2】:

你能在设置器中加入一些逻辑,这样当所有设置器都被调用后,你就可以像这样创建命令

public class Order
{
    private string name;
    [XmlAttribute("Name")]
    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            if (name != value)
            {
                name = value;
                SetupCommandIfPossible();
            }

        }
    }

    private string tid;
    [XmlAttribute("TID")]
    public string TID
    {
        get
        {
            return tid;
        }
        set
        {
            if (tid != value)
            {
                tid = value;
                SetupCommandIfPossible();
            }
        }
    }


    private Command command;
    [XmlAttribute("Command")]
    public string Command
    {
        get
        {
            return command.Name;
        }
        set
        {
            SetupCommandIfPossible();
        }
    }

    public void SetupCommandIfPossible()
    {
         if (!string.IsNullOrEmpty(tid) && !string.IsNullOrEmpty(name) && command == null)
         {             
            command = new Command(TID, Name);
         }
    }

    public Order()
    {

    }
}

【讨论】:

  • 我想过这个,我希望这是一些更优雅的解决方案。 :(
  • 这没有错,它比基于属性的方法更可测试
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-15
  • 2018-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-20
  • 1970-01-01
相关资源
最近更新 更多