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

时间:2018-04-12 06:23:10

标签: c# linq lambda stringbuilder

我试图附加一个字符串列表(> 10),所以为了避免创建很多字符串,我使用的是StringBuilder。如果有人解释为什么会发生这种情况,那就太好了。

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

4 个答案:

答案 0 :(得分:4)

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

正如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等......当它内置于“{1}}循环中时,无需手动”框架。

您可能还想考虑使用ToLowerInvariant代替ToLower,具体取决于您要做的事情。套管非常复杂。

答案 1 :(得分:2)

使用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();

答案 2 :(得分:1)

LINQ方法Selectlazy。 因此,lst.Select(str => sb.Append(str.ToLower()));不会更改sb

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

来自@thehennyy:

您还可以使用方法List.ForEach

答案 3 :(得分:0)

您还可以将.Aggregate字符串添加到构建器中 - 使用每个.Append返回新StringBuilder引用的事实。

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

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