1

LINQtoXML機能構築がどのように機能するかを理解しようとしています。

次のサンプルXMLがあります。

string xml = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
                    <People>
                      <Person firstName=""John"" lastName=""Doe"">
                        <ContactDetails>
                          <EmailAddress>john@unknown.com</EmailAddress>
                        </ContactDetails>
                      </Person>
                      <Person firstName=""Jane"" lastName=""Doe"">
                        <ContactDetails>
                          <EmailAddress>jane@unknown.com</EmailAddress>
                          <PhoneNumber>001122334455</PhoneNumber>
                        </ContactDetails>
                      </Person>
                    </People>";

タグにIsMale属性を追加し、存在しない場合はaを追加して、このXMLを変更しようとしています。PersonPhoneNumber

手続き型コードを使用すると、このコードを簡単に記述できます。

XElement root = XElement.Parse(xml);

foreach (XElement p in root.Descendants("Person"))
{
    string name =  (string)p.Attribute("firstName") + (string)p.Attribute("lastName");
    p.Add(new XAttribute("IsMale", IsMale(name)));

    XElement contactDetails = p.Element("ContactDetails");

    if (!contactDetails.Descendants("PhoneNumber").Any())
    {
        contactDetails.Add(new XElement("PhoneNumber", "001122334455"));
    }
}

しかし、MSDNのドキュメントには、FunctionalConstructionの保守がより簡単で優れている必要があると記載されています。そこで、FunctionalConstructionで同じサンプルを書いてみました。

XElement root = XElement.Parse(xml);

XElement newTree = new XElement("People",
    from p in root.Descendants("Person")
    let name = (string)p.Attribute("firstName") + (string)p.Attribute("lastName")
    let contactDetails = p.Element("ContactDetails")
    select new XElement("Person",
        new XAttribute("IsMale", IsMale(name)),
        p.Attributes(),
        new XElement("ContactDetails",
            contactDetails.Element("EmailAddress"),
            contactDetails.Element("PhoneNumber") ?? new XElement("PhoneNumber", "1122334455")
        )));

私かもしれませんが、このコードの方が読みやすいとは思いません。

機能構造を改善するにはどうすればよいですか?このコードを書くためのより良い方法はありますか?

4

3 に答える 3

1

あなたが参照したmsdnの記事に記載されているように、それはあなたが何をしているかによって異なります。xml に多くの変更を加えている場合、非機能的なアプローチは複雑になり、理解しにくくなります。この場合、どのような結果になるでしょうか?

foreach (XElement p in doc.Descendants("Person"))
{
    var name = (string)p.Attribute("firstName") + " " + (string)p.Attribute("lastName");
    int age = (int)p.Attribute("age");
    p.RemoveAttributes();
    p.SetAttributeValue("isMale", IsMale(name));
    p.SetAttributeValue("name", name);
    p.SetAttributeValue("age", age);
    p.RemoveNodes();
    p.Name = "Human";
}

一目でわかると思います。この例は、私にとってはあまり説明的ではありません。また、変更後にどの構造に xml があるかわかりません。

XElement people = 
new XElement("People",
    from p in doc.Descendants("Person")
    let name = (string)p.Attribute("firstName") + " " +  (string)p.Attribute("lastName")
    select new XElement("Human",
                    new XAttribute("isMale", IsMale(name)),
                    new XAttribute("name", name),
                    p.Attribute("age")
    )
);

私に関しては、2 番目の例は結果を説明し、xml 構造をよりよく示しています。したがって、既存の xml に小さな変更を加える必要がある場合は、非機能的なアプローチを使用します。そして、大きな変更には機能的なアプローチを採用します。とは?主観的な部分だと思います。

ところで、結果として、名前と姓の代わりにage属性を残して1つの属性のみが必要です。また、要素nameの代わりに、要素が必要です:PersonHuman

<People>
  <Human isMale="false" name="John Doe" age="28" />
  <Human isMale="true" name="Jane Doe" age="27" />
</People>
于 2013-01-18T09:10:55.977 に答える
0

機能をもう少し分割することで、特にクエリで呼び出されているコンストラクターをすべて非表示にすることで、コードの表現力を高めることができる場合があります。いくつかのユーティリティ関数をお勧めします。

XElement PersonWithGender(XElement person)
{
    string name = (string)p.Attribute("firstName") + (string)p.Attribute("lastName");
    XAttribute genderAttribute = new XAttribute("isMale", IsMale(name));
    return new XElement(genderAttribute, person.Attributes);
}

XElement PersonWithPhoneNumber(XElement person)
{
    XElement contactDetails = person.Element("ContactDetails");
    XElement emailAddress = contactDetails.Element("EmailAddress");
    XElement phoneNumber = contactDetails.Element("PhoneNumber") ?? new XElement("PhoneNumber", "1122334455");

    return new XElement("ContactDetails", emailAddress, phoneNumber);
}

これらの関数はそれぞれ、最初の XElement を新しい改良された XElement にマップするため、クエリにうまく適合するはずです。一方の結果を他方にフィー​​ドすると、クエリは次のようになります。

XElement newTree = new XElement("People",
    from p in root.Descendants("Person")
    let pWithGender = PersonWithGender(p)
    select PersonWithPhoneNumber(pWithGender));

これは、関数型プログラミングに期待される簡潔さと表現力に近づいていると思います。新しい関数のそれぞれは十分に短いため、それほど労力をかけずに調べることができ、クエリ自体がその意図をより明確に宣言するようになりました。

于 2013-01-18T10:27:28.013 に答える
0

関数コンストラクターを使用するようにという Microsoft のアドバイスの一部は、最初に静的 XML リソースを排除することです。最初の XML 文字列が外部ソースからのものである場合は、それを読み込んで変更し、返す必要があります。

ただし、静的 XML が変更を行う同じコード内から取得され、データが直接利用できる場合は、関数コンストラクターを使用して、変更が既に行われたコードを作成します。

Person[] peopleData = new Person[]
{
   new Person("John", "Doe", "john@unknown.com", ""),
   new Person("Jane", "Doe", "jane@unknown.com", "001122334455")
}

XElement people = 
   new XElement("People",
      from p in peopleData
      select new XElement("Human",
                new XAttribute("isMale", p.IsMale),
                new XAttribute("name", p.FullName),
                new XAttribute("age", p.Age)
      )
   );

このアプローチは、元の XML とほぼ同じくらい読みやすいですが、元の XML の解析が省略されているため、はるかに高速です。

于 2015-06-30T18:47:05.067 に答える