2017-05-08 8 views
2

私はLinqを使ってXElementの子をソートしようとしていて、既存の子をソート済みのものに置き換えようとしています。ISortedEnumerable <XElement>をXElementに追加するにはどうすればよいですか?

まず私はXElementオブジェクトを作成します。その後、私は、ソートノード

XElement WithLinq = 
      new XElement("Names", 
       from cust in Customers.AsEnumerable() 
       select 
        new XElement("Customer", 
         new XAttribute("ID", cust.ID), 
         new XElement("Name", cust.Name), 
         new XElement("Purchases", 
         from pur in cust.Purchases 
         select 
          new XElement("Purchase", 
           new XElement("Produkt",pur.Description), 
           new XAttribute("ID",pur.ID), 
           new XElement("Price",pur.Price), 
           new XComment("teraz daty"), 
           new XElement("Date",pur.Date), //Formatuje DateTime zgodnie z normami XMLa 
           new XElement("DataAleNieDoKonca",pur.Date.ToString(CultureInfo.InvariantCulture)))))  
         ); 

var NowaKolejnosc = WithLinq.Elements().Last().Elements().OrderBy(n => n.Name).ThenBy(n => n.Value); 

し、それらを置き換えます

WithLinq.Elements().Last().ReplaceNodes(NowaKolejnosc); 

をしかし、私は実行時例外を取得:ArgumentExceptionが「コ「IComparable」要素を実装するために使用されます。翻訳:少なくとも1つのオブジェクトがIComparableを実装する必要があります。

例外が発生している原因と解決方法を理解できません。

答えて

2

XElement.NameSystem.Xml.Linq.XNameであるため、エラーが発生しています。 XNameにはIComparableが実装されていません。

XNameはSystem.Stringの値をラップし、ToStringをオーバーライドしてSystem.Stringの値を返します。

System.StringIComparableを実装しているので、私たちは正しく、正常にOrderByを呼び出すために、この知識を活用することができます。論理的に、ラップされた文字列を比較したいので、これには望ましいセマンティクスがあります。

WithLinq.Elements().Last().Elements().OrderBy(n => n.Name.ToString()).ThenBy(n => n.Value) 

複数のLINQ演算子を使用する場合、クエリ式の構文を使用すると読み易くなります。

from element in WithLinq.Elements().Last().Elements() 
orderby element.Name.ToString(), element.Value 
select element 
1

これは、Aluan Haddadの回答に基づいて作成されたコメントです。

提案:XName.ToString()の代わりにXName.LocalNameを使用することを検討してください:

element.Name.LocalNameプロパティを直接操作することは適切である、XMLはXMLで名前空間が必要とされていない名前空間またはを使用していないことを提供特定の操作のために。

大きい(> 1GB)XMLファイルを処理する場合、XName.LocalNameXName.ToString()をスワップすることで中程度のパフォーマンス向上が見られました。

偶然にもかかわらず、この変更は、繰り返しの並べ替えと比較を必要とする1時間の長いプログラムで約半ダース分を節約しました。他の文脈では、YMMV。

いくつかの文脈では、ここでの違いはthe reference sourceを経由して、次のとおりです。

/// <summary> 
/// Returns the expanded XML name in the format: {namespaceName}localName. 
/// </summary> 
public override string ToString() { 
    if (ns.NamespaceName.Length == 0) return localName; 
    return "{" + ns.NamespaceName + "}" + localName; 
} 
/// <summary> 
/// Gets the local (unqualified) part of the name. 
/// </summary> 
/// <seealso cref="XName.Namespace"/> 
public string LocalName { 
    get { return localName; } 
} 
関連する問題