82

LINQ to XML XElement のディープ コピーを作成したいと考えています。これを行う理由は、(同じドキュメント内に) 変更されたコピーを作成したいノードがドキュメント内にあるためです。これを行う方法がわかりません。

要素を XML 文字列に変換して再解析することもできますが、もっと良い方法はないかと考えています。

4

5 に答える 5

148

再解析する必要はありません。XElement のコンストラクターの 1 つは、別の XElement を受け取り、そのディープ コピーを作成します。

XElement original = new XElement("original");
XElement deepCopy = new XElement(original);

次に示すのは、デモ用の単体テストです。

[TestMethod]
public void XElementShallowCopyShouldOnlyCopyReference()
{
    XElement original = new XElement("original");
    XElement shallowCopy = original;
    shallowCopy.Name = "copy";
    Assert.AreEqual("copy", original.Name);
}

[TestMethod]
public void ShouldGetXElementDeepCopyUsingConstructorArgument()
{
    XElement original = new XElement("original");
    XElement deepCopy = new XElement(original);
    deepCopy.Name = "copy";
    Assert.AreEqual("original", original.Name);
    Assert.AreEqual("copy", deepCopy.Name);
}
于 2008-12-10T15:35:21.423 に答える
9

ToString と reparse メソッドが最善の方法のようです。コードは次のとおりです。

XElement copy = XElement.Parse(original.ToString());
于 2008-10-16T18:17:41.823 に答える
4

一言で言えば、C#3.0から直接持ち上げた:

ノードまたは属性が要素に追加されると (機能構築または Add メソッドを介して)、ノードまたは属性の Parent プロパティがその要素に設定されます。ノードは 1 つの親要素のみを持つことができます。既に親になっているノードを 2 番目の親に追加すると、ノードは自動的にディープ クローンされます。次の例では、顧客ごとに個別の住所のコピーがあります。

var address = new XElement ("address",
                  new XElement ("street", "Lawley St"),
                  new XElement ("town", "North Beach")
              );
var customer1 = new XElement ("customer1", address);
var customer2 = new XElement ("customer2", address);

customer1.Element ("address").Element ("street").Value = "Another St";
Console.WriteLine (
  customer2.Element ("address").Element ("street").Value);   // Lawley St

この自動複製により、X-DOM オブジェクトのインスタンス化に副作用がなくなります。これは、関数型プログラミングのもう 1 つの特徴です。

于 2008-10-17T14:00:47.347 に答える
-1

これはうまくいくはずです:

var copy = new XElement(original.Name, original.Attributes(),
                        original.Elements() );
于 2013-08-16T15:26:17.170 に答える
-3

XNode スタイル ツリーのディープ コピーを実行できる既存のメカニズムがあるとは思えません。あなたには2つの選択肢が残っていると思います。

  1. あなたが提案したように、文字列に変換してからツリーに戻します
  2. 訪問者パターンで自分自身に書き込みます

訪問者パターンは確かに可能ですが、テストにはかなりの作業が必要です。あなたの最良の選択肢は#1だと思います。

于 2008-10-16T17:58:21.517 に答える