在 lambda 表达式中使用 StringBuilder.Append() 会生成一个空字符串

Using StringBuilder.Append() in a lambda expression is producing an empty string

我正在尝试附加一个字符串列表(> 10),因此为了避免创建大量字符串,我使用 StringBuilder.It 如果有人解释为什么会这样,那就太好了..

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        var lst = new List<string>(){"A", "B", "C"};
        StringBuilder sb = new StringBuilder();
        lst.Select(str => sb.Append(str.ToLower()));
        Console.Write("Output: {0}", sb.ToString());
    }
}

Run the code here-dotnetfiddle

LINQ 方法 Selectlazy。 所以,lst.Select(str => sb.Append(str.ToLower())); 不会改变 sb

要查看效果,您必须遍历结果: lst.Select(str => sb.Append(str.ToLower())).ToArray(); 例如。

来自@thehennyy:

你也可以使用方法List.ForEach

使用ForEach代替Select:

static void Main(string[] args)
{
    var lst = new List<string>() { "A", "B", "C" };
    StringBuilder sb = new StringBuilder();
    lst.ForEach(str => sb.Append(str.ToLower()));
    Console.Write("Output: {0}", sb.ToString());
    Console.ReadKey();
}

或者您可以只使用 LINQ Aggregate:

var lst = new List<string>() { "A", "B", "C" };
string result = lst.Aggregate((x, y) => x + y).ToLower();

正如其他答案中所指出的,Select 的懒惰是这里的问题所在。我要更广泛地补充一点,在 LINQ 查询中使用副作用(例如附加到 StringBuilder)通常不是一个好主意。每个选择器、条件等理想情况下都应该没有副作用。

正如 Gilad 指出的那样,您可以在这种情况下使用 string.Concat - 但您需要使用 Select 将每个值转换为小写,除非您想在事实(我怀疑在某些极端情况下可能会有不同的结果)。

所以要么:

var list = new List<string> { "A", "B", "C" };
string result = string.Concat(list.Select(str => str.ToLower()));

或者,结果可能不同,但创建的字符串更少:

var list = new List<string> { "A", "B", "C" };
string result = string.Concat(list).ToLower();

鉴于 string.Concat 的存在,我不会开始使用 foreach 循环或 List.ForEach 等...没有必要这样做 "manually" 时它内置于框架中。

您可能还想考虑使用 ToLowerInvariant 而不是 ToLower,具体取决于您要执行的操作。外壳出奇的复杂。

您还可以 .Aggregate 将您的字符串放入构建器中 - 使用每个 .Append returns 一个新的 StringBuilder 引用这一事实。

StringBuilder result = lst.Aggregate(new StringBuilder(), (sb, str) => sb.Append(str));

这样您就不会滥用 .Select 迭代器,也不会对查询造成副作用。