为啥 XElement 的行为不像引用类型?
Posted
技术标签:
【中文标题】为啥 XElement 的行为不像引用类型?【英文标题】:Why does XElement not behave like a reference type?为什么 XElement 的行为不像引用类型? 【发布时间】:2021-08-18 15:30:24 【问题描述】:我注意到XElement
是一个类,所以我尝试了类似的方法:
var doc = new XDocument(
new XDeclaration("1.0", "utf8", "yes"),
new XElement("Root")
);
var root = doc.Root;
var com = new XElement("Component", new XAttribute("name", "arm"));
root.Add(com);
root.Add(com);
root.Add(com);
com.Add(new XAttribute("type", 1));
Console.WriteLine(doc);
但输出是:
<Root>
<Component name="arm" type="1" />
<Component name="arm" />
<Component name="arm" />
</Root>
我也试过SetAttributeValue()
,得到了同样的结果。
为什么type属性只附加在第一个组件上?
【问题讨论】:
因为它是made that way。 “当添加XNode
或 XAttribute
对象时,如果新内容没有父对象,则对象只是附加到 XML 树。如果新内容已经是父对象并且是另一个 XML 树的一部分,那么新内容被克隆,并且新克隆的内容被附加到 XML 树中。”如果您考虑一下,在询问文档顺序时,尝试维护引用语义会导致非常不直观的结果。
为什么不把com.Add(new XAttribute("type", 1));
放在root.Add(com);
前面,而不是后面?
如果您更喜欢查看sources,那么您会看到它会调用CloneNode()
方法来进行后续调用(因为将设置com
的父级)。通过修改com
实例,您只会更改未克隆的第一个节点。
@JeroenMostert 除非有 dup-target(我找不到),否则您可能希望将此作为答案发布。
【参考方案1】:
我在下面给出了第二个答案 - 更好,因为它给出了具体的设计原因 - 但留下了这个答案,因为它证明内部副本已经发生。
作为一个类并不能提供关于该类的行为或应该如何对待的线索。
使用调试器
每个节点都有不同的哈希值,因此必须假定为不同的对象(因此推测Add()
期间正在进行复制)。
如果你可以改变你的操作顺序,这就解决了问题
static void X()
var doc = new XDocument(
new XDeclaration("1.0", "utf8", "yes"),
new XElement("Root")
);
var root = doc.Root;
var com = new XElement("Component", new XAttribute("name", "arm"));
com.Add(new XAttribute("type", 1));
root.Add(com);
root.Add(com);
root.Add(com);
Console.WriteLine(doc);
给予
<Root>
<Component name="arm" type="1" />
<Component name="arm" type="1" />
<Component name="arm" type="1" />
</Root>
【讨论】:
它没有解决问题,它隐藏了它。所有节点上存在的属性可能会让您认为它们确实是同一个实例,但事实并非如此。它们和以前一样是三个副本。 @GSerg:我同意它不直观,但这并没有错。显然,这是设计行为。我建议更改类的使用以修复行为,您是否建议更改类以适应这种类型的使用?【参考方案2】:我最初的答案是(本质上是“设计”),这就是为什么......
来自MS Documentation(并点击相关链接)您会发现
XElement
继承 XContainer
继承 XNode
XContainer
具有方法 Add()
和属性 FirstNode
和 LastNode
XNode
具有属性 NextNode
和 PreviousNode
如果Add()
盲目地添加对同一对象的引用,而没有在必要时创建副本以避免多重引用,那么如何避免循环引用?在上面的示例中,FirstNode
和 FirstNode.NextNode
将引用同一个对象。
【讨论】:
以上是关于为啥 XElement 的行为不像引用类型?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在向量类中实现 operator= 时返回 const 引用