好的,發現它,雖然我不完全明白答案。下面是產生期望結果的兩個表達式,一個使用「讓」,另一個使用「選擇:」
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")
;
第一「選擇」。選擇(分=> sub.Descendants(「機器人」) ),在第一兩個表達式的,「讓」的形式,產生XElements的可枚舉的可枚舉,或者更精確地說,
System.Linq.Enumerable+WhereSelectEnumerableIterator`2[System.Xml.Linq.XElement,System.Collections.Generic.IEnumerable`1[System.Xml.Linq.XElement]]
第一「選擇」。選擇(分=>新的{ bots = sub.Descendants(「bot」)),在這兩個表達式中的第二個表達式中,「選擇」表單生成一個匿名類型的枚舉,其中每個匿名類型都包含一個可枚舉的,名爲「機器人」的XElements:
System.Linq.Enumerable+WhereSelectEnumerableIterator`2[System.Xml.Linq.XElement,<>f__AnonymousType0`1[System.Collections.Generic.IEnumerable`1[System....
我們希望將每個內部枚舉變換爲{fst,snd}對。首先注意以下兩個表達式產生相同的結果,但語義不同,如下所示。這兩個表達式之間的唯一區別是第一行在第3行有「Let」,第二行在第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")
;
中的類型「機器人」的外「讓」中的第一個表達式從「機器人」的類型的不同之處外的第二表達式「選擇」。在「機器人」「讓」的類型爲(大約)IEnumerable<IEnumerable<XElement>>
(它的全稱是
System.Linq.Enumerable+WhereSelectEnumerableIterator`2[System.Xml.Linq.XElement,System.Collections.Generic.IEnumerable`1[System.Xml.Linq.XElement]]
我們可以通過選擇在每個「殭屍」中的「機器人」是內部詳細看一個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
由並行分析上述,我們看到,每個「機器人」,在「機器人」是一個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)
人們很容易想到這些語義上是相同的,但他們沒有。在「選擇」表單中,類型級別的隱式包裝比「Let」表單中的隱式包裝多一層,反之亦然,具體取決於您的觀點。另外,顯然,「讓」運行一次,結果是.Select(sub => sub.Descendants(「bot」)),而「Select」運行多次,每次運行一次結果 以下是錯誤的,因爲它忽略了「包裝水平」。
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")
;
}
是不是'let'在C#表達式語言只是語法糖嗎?我沒有意識到任何'Let'擴展方法,您可以使用方法語法。 – 2011-04-26 10:42:21
System.Interactive中絕對有一個Let擴展方法。下面是正確編譯(但不會做我想做的:(root.Descendants( 「子」) \t \t。讓(機器人=>機器人 \t \t \t。選擇(BOT => BOT)) 樣本\t \t使用.dump( 「塔底」) – 2011-04-26 14:45:50
這裏還有一個使用放手的那個作品(但不會做我想做的:) \t root.Descendants( 「子」) \t \t。讓(機器人=> bots.Zip( (a,b)=> new {a = a,b = b})) \t \t .Dump(「bottoms2」) – 2011-04-26 15:41:53