[英]C# XMLSerializer and sequence of attribute serialization
I have a problem with XML deserialization. 我对XML反序列化有问题。 Well, lets suppose that my class have three properties:
好吧,假设我的课有三个属性:
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()
{
}
}
As you can see, I need to create an object Command with parameter constructor on deserialize Command property - but I need TID and Name attribute to this. 如您所见,我需要在反序列化Command属性上创建一个带有参数构造函数的Command对象,但是对此我需要TID和Name属性。 I need to be sure that these fields are not null.
我需要确保这些字段不为空。 As I observed, XmlSerializer is deserializing attributes according to sequence how user write it.
正如我观察到的,XmlSerializer根据用户编写序列的顺序反序列化属性。 For example:
例如:
<Order Command="SetPlus" TID="W403" Name="SomeName" />
In this case, first serialized will be Command attribute. 在这种情况下,首先序列化的将是Command属性。 But I don't have TID and Name property yet!
但是我还没有TID和Name属性! I can't trust user that he will pass attributes in correct sequence like:
我不能相信用户他会按正确的顺序传递属性,例如:
<Order TID="W403" Name="SomeName" Command="SetPlus" />
Well, I need some event or something I can call on deserialize finish OR I need to be sure that XmlSerializer will deserialize attributes in sequence like I want. 好吧,我需要一些事件或可以反序列化完成的东西,或者我需要确保XmlSerializer将按我想要的顺序反序列化属性。 The only thing I found is:
我发现的唯一是:
[XmlElement(Order = 1)]
or 要么
[XmlElementAttribute(Order = 1)]
But it doesn't work with XmlAttribute. 但这不适用于XmlAttribute。
Is some way to do this? 有什么办法做到这一点? Hope I explained my problem clearly.
希望我能清楚地解释我的问题。
If your Command
only depends on the TID
and the Name
why do you even serialize it? 如果您的
Command
仅取决于TID
和Name
为什么还要序列化它? This is just redundant information. 这只是多余的信息。
You should use the [XmlIgnore]
attribute on the Command
property. 您应该在
Command
属性上使用[XmlIgnore]
属性。 After that you can implement a kind of lazy load method for your Command
property. 之后,您可以为
Command
属性实现一种惰性加载方法。
By the way: Your code is wrong anyway. 顺便说一句:您的代码仍然是错误的。 On the
set
part of your Command
property, you don't even use the value the user passed in. It would be better if you'd do it like this: 在
Command
属性的set
部分上,甚至不使用用户传入的值。如果这样做,会更好:
private Command command;
[XmlIgnore]
public string Command
{
get
{
if (command == null)
{
command = new Command(TID, Name));
}
return command.Name;
}
}
edit: 编辑:
ok after you changed your post and actually use the value of the Command
property setter, the solution is a little trickier and there are multiple ways. 好的,在您更改帖子并实际使用
Command
属性设置器的值之后,解决方案会有些棘手,并且有多种方法。
What I'd probably do: 我可能会做什么:
CommandName
to your class, which just is a simple string property (with getter), also add and XmlAttribute
to this property CommandName
属性,这只是一个简单的字符串属性(带有getter),还向该属性添加XmlAttribute
[XmlIgnore]
to your Command
property, and take my code from above (lazy initialization), return the command using the new CommandName
property ( new Command(TID, Name, CommandName)
) [XmlIgnore]
添加到您的Command
属性,并从上方获取我的代码(延迟初始化),使用新的CommandName
属性( new Command(TID, Name, CommandName)
)返回命令 Personally I would even add a setter to the CommandName
property and let the Command
property actually return a Command
and not a string
. 我个人甚至会在
CommandName
属性中添加一个setter,并让Command
属性实际上返回Command
而不是string
。 In my opinion this would make the code cleaner and more readable. 在我看来,这将使代码更整洁,更易读。
For clarification, this is how my class would look like: 为了澄清,这是我的班级样子:
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()
{
}
}
Can you put some logic in the setters so that when all the setters have been called you then create the command like so 您可以在设置器中添加一些逻辑,以便在调用所有设置器后,按如下所示创建命令
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()
{
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.