为什么XElement不能像引用类型一样工作?

6

我注意到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属性只附加在第一个组件上?


13
因为它是这样制作的。如果添加 XNodeXAttribute 对象,新内容没有父级,则这些对象将被简单地附加到 XML 树上。如果新内容已经具有父级并且属于另一个 XML 树,则会克隆新内容,并将新克隆的内容附加到 XML 树上。如果您考虑一下,试图维护引用语义将导致非常不直观的结果,当询问文档顺序时。 - Jeroen Mostert
为什么不在root.Add(com);之前放置com.Add(new XAttribute("type", 1));,而不是之后呢? - Auditive
1
如果您想查看源代码,那么您会发现它会为后续调用调用CloneNode()方法(因为com的父级将被设置)。通过修改com实例,您只会更改未克隆的第一个节点。 - Sinatr
4
@JeroenMostert,除非有重复目标(我找不到),否则您可能希望将此作为答案发布。 - 41686d6564 stands w. Palestine
2个回答

1

我在下面给出了第二个答案 - 更好的原因是它提供了一个具体的设计原因 - 但我留下了这个答案,因为它证明了内部复制已经发生。


一个类的存在并不能说明这个类的行为或者应该如何对待它。

使用调试器

Hashcodes per node

每个节点都有不同的哈希值,因此必须假定它们是不同的对象(因此在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>

1
它并没有解决问题,而是隐藏了它。所有节点上属性的存在可能会让你认为它们确实是同一个实例,但它们并不是。它们仍然像以前一样有三个副本。 - GSerg
1
@GSerg:我同意这不是很直观,但这并不意味着它是错误的。显然,这是按设计行为。我建议使用该类应更改以修复此行为,您是否建议更改该类以适应此类型的使用? - AlanK

1

我的原始答案仍然有效(基本上是“按设计”),下面是一个原因...

MS文档(并跟随相关链接)中,你会发现:

  • XElement继承XContainerXContainer继承XNode
  • XContainer有方法Add()和属性FirstNodeLastNode
  • XNode有属性NextNodePreviousNode

如果Add()盲目地添加对同一对象的引用,而不在必要时创建副本以避免多重引用,那么如何避免循环引用?在你上面的示例中,FirstNodeFirstNode.NextNode将引用相同的对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接