0

入れ子になった XElement の定義と Linq 式のペアで構成される次のサンプルを検討してください。期待どおりに機能する最初の式は、bots を取得することによって作成された tmp を選択することにより、最下位レベルで最初と最後の XElements を繰り返しフェッチし (bots の場合)、名前 "bots ." 2 番目の式は、"Let" を使用するだけで同じことを試みますが、まったく機能しません。まず、コンパイラは型推論が機能していないと文句を言います。次に、明示的な型を入れると、IObservable になり、さらに失われます。私はこれがまったく簡単なことだと思っていましたが、失敗に非常に驚き、戸惑いました。誰かが見てアドバイスする瞬間があれば、私は感謝します. 以下をLinqPadに貼り付けることができます。

var root = new XElement("root",
    new XElement("sub",
        new XElement("bot", new XAttribute("foo", 1)),
        new XElement("bot", new XAttribute("foo", 2))),
    new XElement("sub",
        new XElement("bot", new XAttribute("foo", 3)),
        new XElement("bot", new XAttribute("foo", 4))));
root.Dump("root");

root.Descendants("sub")
    .Select(sub => new {bots = sub.Descendants("bot")})
    .Select(tmp => new{fst = tmp.bots.First(), snd = tmp.bots.Last()})
    .Dump("bottoms")
    ;

root.Descendants("sub")
    .Select(sub => sub.Descendants("bot"))
    .Let(bots => new{fst = bots.First(), snd = bots.Last()})
    .Dump("bottoms2")
    ;
4

2 に答える 2

1

letのような変換を単純化する単なるキーワードですtmp => new{fst = tmp.bots.First(), snd = tmp.bots.Last()}Let拡張メソッドを使用するのではなく、次のSelectメソッドを使用するだけです。

root.Descendants("sub")
    .Select(sub => sub.Descendants("bot"))
    .Select(bots => new{fst = bots.First(), snd = bots.Last()})
    .Dump("bottoms2");
于 2011-04-26T18:25:00.147 に答える
0

わかりました、答えは完全にはわかりませんが、見つけました。1 つは "Let" を使用し、もう 1 つは "Select:" を使用して、目的の結果を生成する 2 つの式を次に示します。

root.Descendants("sub")
    .Select(sub => sub.Descendants("bot"))
    .Let(bots => bots.Select(bot => new{fst = bot.First(), snd = bot.Last()}))
    .Dump("bottoms2")
    ;

root.Descendants("sub")
    .Select(sub => new {bots = sub.Descendants("bot")})
    .Select(tmp => new{fst = tmp.bots.First(), snd = tmp.bots.Last()})
    .Dump("bottoms")
    ;

最初の "Select" .Select(sub => sub.Descendants("bot")) は、2 つの式の最初の "Let" 形式で、XElements の列挙型の列挙型を生成します。より正確には、

System.Linq.Enumerable+WhereSelectEnumerableIterator`2[System.Xml.Linq.XElement,System.Collections.Generic.IEnumerable`1[System.Xml.Linq.XElement]]

最初の "Select" .Select(sub => new {bots = sub.Descendants("bot")) は、2 つの式のうちの 2 番目の "Select" フォームで、列挙可能な匿名型を生成します。 XElements の「ボット」という名前の列挙可能なものが含まれています。

System.Linq.Enumerable+WhereSelectEnumerableIterator`2[System.Xml.Linq.XElement,<>f__AnonymousType0`1[System.Collections.Generic.IEnumerable`1[System....

内部列挙型のそれぞれを {fst, snd} ペアに変換します。以下に示すように、次の 2 つの式は同じ結果を生成しますが、意味的には同一ではないことに注意してください。これら 2 つの式の唯一の違いは、最初の式の 3 行目に「Let」があり、2 番目の式の 3 行目に「Select」があることです。変換。

root.Descendants("sub")
    .Select(sub => sub.Descendants("bot"))
    .Let(bots => bots.Select(bot => bot))
    .Dump("bottoms3")
    ;

root.Descendants("sub")
    .Select(sub => sub.Descendants("bot"))
    .Select(bots => bots.Select(bot => bot))
    .Dump("bottoms4")
    ;

最初の式の外側の「Let」の「bots」のタイプは、2 番目の式の外側の「Select」の「bots」のタイプとは異なります。「レッツ」における「ボット」の種類は(ざっくり)IEnumerable<IEnumerable<XElement>>(フルネームは

System.Linq.Enumerable+WhereSelectEnumerableIterator`2[System.Xml.Linq.XElement,System.Collections.Generic.IEnumerable`1[System.Xml.Linq.XElement]]

「bots」の各「bot」が次の内部を選択することで、より詳細に確認できますIEnumerable<XElement>

root.Descendants("sub")
    .Select(sub => sub.Descendants("bot"))
    .Let(bots => 
    {
        bots.GetType().Dump("bots in Let"); 
        return bots.Select(bot => bot.GetType());
    })
    .Dump("Types of bots inside the LET")
    ;

Types of bots inside the LET

IEnumerable<Type> (2 items)

typeof (IEnumerable<XElement>)

typeof (IEnumerable<XElement>)

外側の「選択」では、「ボット」の種類は

System.Xml.Linq.XContainer+<GetDescendants>d__a

上記と並行して分析すると、「bots」内の各「bot」は何かの IEnumerable であり、何かは XElement であることがわかります。

    root.Descendants("sub")
    .Select(sub => sub.Descendants("bot"))
    .Let(bots => 
    {
        bots.GetType().Dump("bots in Let"); 
        return bots.Select(bot => bot.GetType());
    })
    .Dump("Types of bots inside the LET")
    ;

Types of bots inside the SELECT

IEnumerable<IEnumerable<Type>> (2 items)

IEnumerable<Type> (2 items)

typeof (XElement)

typeof (XElement)

IEnumerable<Type> (2 items)

typeof (XElement)

typeof (XElement)

これらは意味的に同じであると考えがちですが、そうではありません。「Select」フォームでは、「Let」フォームよりもタイプ レベルで 1 レベル以上の暗黙的なパッケージングが行われます。視点によっては、その逆もあります。

また、明らかに、「Let」は .Select(sub => sub.Descendants("bot")) の結果に対して 1 回「実行」しますが、「Select」は複数回実行され、各結果に対して 1 回実行されます。その「パッケージのレベル」は無視されます。

root.Descendants("sub")
    .Select(sub => sub.Descendants("bot"))
    .Let(bots => new{fst = bots.First(), snd = bots.Last()})
    .Dump("bottoms2")
    ;

私が言ったように、私はまだこの現象のすべての詳細を完全に理解していません. おそらく、さらにいくつかの例と、それについての別の夜の睡眠不足により、私はそれについてより洗練された直感を開発し始めるでしょう. この微妙な部分を試してみたいと思っている場合に備えて、LinqPad の完全なスクリプトを次に示します。

void Main()
{
Console.WriteLine ("Here is a sample data set, as XML:");
var root = new XElement("root",
new XElement("sub",
    new XElement("bot", new XAttribute("foo", 1)),
    new XElement("bot", new XAttribute("foo", 2))),
new XElement("sub",
    new XElement("bot", new XAttribute("foo", 3)),
    new XElement("bot", new XAttribute("foo", 4))));
root.Dump("root");

Console.WriteLine ("The following two expressions produce the same results:");

root.Descendants("sub")
    .Select(sub => sub.Descendants("bot"))
    .Let(bots => bots.Select(bot => new{fst = bot.First(), snd = bot.Last()}))
    .Dump("LET form: bottoms1")
    ;

root.Descendants("sub")
    .Select(sub => new {bots = sub.Descendants("bot")})
    .Select(tmp => new{fst = tmp.bots.First(), snd = tmp.bots.Last()})
    .Dump("SELECT form: bottoms2")
    ;

Console.WriteLine ("Analysis of LET form");

root.Descendants("sub")
    .Select(sub => sub.Descendants("bot"))
    .Dump("Top-Level Select in the \"Let\" form:")
    ;

root.Descendants("sub")
    .Select(sub => sub.Descendants("bot"))
    .GetType()
    .Dump("Type of the top-Level Select in the \"Let\" form:")
    ;

root.Descendants("sub")
    .Select(sub => sub.Descendants("bot"))
    .Let(bots => bots.Select(bot => bot))
    .Dump("Let(bots => bots.Select(bot => bot))")
    ;

root.Descendants("sub")
    .Select(sub => sub.Descendants("bot"))
    .Let(bots => 
    {
        bots.GetType().Dump("bots in Let"); 
        return bots.Select(bot => bot.GetType());
    })
    .Dump("Types of bots inside the LET")
    ;

Console.WriteLine ("Analysis of SELECT form");

root.Descendants("sub")
    .Select(sub => new {bots = sub.Descendants("bot")})
    .Dump("Top-level Select in the \"Select\" form:")
    ;

root.Descendants("sub")
    .Select(sub => new {bots = sub.Descendants("bot")})
    .GetType()
    .Dump("Type of the top-level Select in the \"Select\" form:")
    ;

root.Descendants("sub")
    .Select(sub => sub.Descendants("bot"))
    .Select(bots => bots.Select(bot => bot))
    .Dump("bots => bots.Select(bot => bot)")
    ;

root.Descendants("sub")
    .Select(sub => sub.Descendants("bot"))
    .Select(bots =>         
    {
        bots.GetType().Dump("bots in Select"); 
        return bots.Select(bot => bot.GetType());
    })
    .Dump("Types of bots inside the SELECT")
    ;
}
于 2011-04-26T18:14:57.447 に答える