C# LINQ 中是否有替代 `let` 关键字的强制性替代方法?

Is there an imperative alternative to the `let` keyword in C# LINQ?

在 C# LINQ 中是否有替代 let 关键字的命令?

例如MSDN documentation 中有声明性 LINQ 示例:

var earlyBirdQuery =
            from sentence in strings
            let words = sentence.Split(' ')
            from word in words
            let w = word.ToLower()
            where w[0] == 'a' || w[0] == 'e'
                || w[0] == 'i' || w[0] == 'o'
                || w[0] == 'u'
            select word;

而且我想用命令式的方式来写。可能吗?

我知道我可以做到以下几点:

var earlyBirdQuery = sentence
.Select(s => s.Split(' '))
.Select(w => w.ToLower())
.Where(w => w[0] == 'a' || w[0] == 'e' || w[0] == 'i' || w[0] == 'o' || w[0] == 'u')
.Select(w => w);

是说命令式的Select具有声明式的from + let的效果还是有其他方式可以模仿letSelectfrom + let?

不完全相同

在这里,您可以使用 SelectMany 来展平嵌套序列。

char[] vowels = new[] { 'a', 'e', 'i', 'o', 'u' };
var earlyBirdQuery = sentence
    .SelectMany(s => s.Split(' '))
    .Select(w => w.ToLower())
    .Where(w => vowels.Contains(w[0]));
// Result contains all words from all sentences beginning with a vowel.

查询中的第一个 let 并不是必需的,因为您可以简单地写 from word in sentence.Split(' ').

您有两个 from 子句。它们的行为很像两个嵌套的 C# for 语句。 SelectMany 打开里面的那个。还有一些情况,你查询一个有集合 属性 的对象,你可以在其中使用 SelectMany。例如:

// Select all files from all subdirectories of the temp directory.
var directory = new DirectoryInfo(@"c:\temp");
IEnumerable<string> files = directory.GetDirectories()
    .SelectMany(d => d.GetFiles())
    .Select(f => f.FullName);

或者,SelectMany 的另一个重载具有结果选择器:

var directory = new DirectoryInfo(@"c:\temp");
IEnumerable<string> files = directory.GetDirectories()
    .SelectMany(d => d.GetFiles(), (d, f) => f.FullName)

在其他情况下,您可以通过创建匿名类型来存储中间结果。例如:

string[] list = new[] { "A", "B" };
var result = from x in list
                let y = x.ToLowerInvariant()
                where y == "a"
                select x + " " + y;

使用扩展方法语法:

string[] list = new[] { "A", "B" };
var result = list
    .Select(x => new { x, y = x.ToLowerInvariant() })
    .Where(a => a.y == "a")
    .Select(a => a.x + " " + a.y);

在某些情况下,您可以使用语句块来替换 let:

...
.Where(word => {
    string lower = word.ToLower();
    return lower.Contains("x") || lower.Contains("y");
})
...