考虑一下:
string test = "";
somestring.ToList().Take(50).Select(
delegate(char x)
{
test += x;
return x;
}
);
现在为什么之后测试是空的?我不关心它的回归,实际上我知道它的IEnumerable。
如果这一切看起来一团糟,那我怎么能把IEnumerable<char>
转换为字符串?
提前感谢..
答案 0 :(得分:21)
因为您没有执行查询。 Linq很懒。当您执行foreach
或ToList
/ ToArray
/ ToDictionary
时,它会被执行。
我建议这样做
string test = new string(somestring.Take(50).ToArray());
甚至使用
string test = somestring.Substring(0, 50);
更多相关内容。 Select
旨在按顺序对每个元素应用某种转换。此操作也称为map
。如果您想从序列中生成单个元素,则为Aggregate
,即reduce
。它不是懒惰,它强制执行查询。
答案 1 :(得分:15)
(其他人解释了为什么它不起作用。)
目前你的问题没有多大意义 - 目前尚不清楚你是否实际处理IEnumerable<char>
或IEnumerable<string>
。 (您的文字建议IEnumerable<string>
;您的代码建议IEnumerable<char>
)。如果它是IEnumerable<string>
并且您使用的是.NET 4,那么它非常简单:
string combined = string.Join("", list.Take(50));
如果您使用的是.NET 3.5,它仍然非常简单:
string combined = string.Join("", list.Take(50).ToArray());
如果你想要字符串之间的分隔符,显然可以使用类似“,”的东西。
如果您正在与一名将军IEnumerable<char>
打交道,请使用
string combined = new string(chars.Take(50).ToArray());
如果您实际上处理要开头的字符串,请使用Substring
:)
答案 2 :(得分:3)
Select
返回IEnumerable<char>
,但您没有在代码中枚举它,因此代理将不会被执行。如果您将其更改为:
string test = "";
somestring.Take(50).Select(
delegate(char x)
{
test += x;
return x;
}
).ToList();
答案 3 :(得分:3)
因为你只声明了序列,但你从未执行过它。如果您在结尾处添加了另一个.ToList()
,那么test
将包含其中的字符。
但是,我强烈建议不要这样做。您正在使用序列的评估来导致副作用。您已经发现结果令人困惑。如果你真的只想要一个序列的前50个项目,只需单独使用Take
:
var partSequence = fullSequence.Take(50);
上面的例子可能是这样写的:
var partString = new string(someString.Take(50).ToArray());
但我确信您已为此目的了解string.Substring()
。
答案 4 :(得分:2)
因为Select
是惰性的,所以只有在使用Select的结果时才会评估传入的函数。
通常,选择使用带副作用的函数是个坏主意。你可能应该使用foreach。
在这种特殊情况下,您可以使用String.Join方法。