是否可以将下面的'foreach'写为LINQ语句,我想更一般的问题是任何for循环都可以被LINQ语句取代。
我对任何潜在的性能成本都不感兴趣,我只对在传统的命令式代码中使用声明性方法的可能性感兴趣。
private static string SomeMethod()
{
if (ListOfResources .Count == 0)
return string.Empty;
var sb = new StringBuilder();
foreach (var resource in ListOfResources )
{
if (sb.Length != 0)
sb.Append(", ");
sb.Append(resource.Id);
}
return sb.ToString();
}
字符串
欢呼
AWC
7条答案
按热度按时间0tdrvxhp1#
当然。见鬼,但你不应该。
查询表达式的目的是 * 表示一个查询操作 *。“for”循环的目的是遍历一个特定的语句,以便多次执行其副作用。这些经常是非常不同的。我鼓励用更高级别的结构来替换循环,这些结构更清楚地查询数据。我强烈反对替换副作用-生成带有查询解析的代码,尽管这样做是可能的。
9vw9lbht2#
一般来说是的,但也有一些特殊的情况是非常困难的。例如,下面的代码在一般情况下不移植到LINQ表达式,除非有大量的黑客攻击。
字符串
原因是使用for循环,可以看到如何在闭包中捕获迭代变量的副作用。LINQ表达式隐藏了迭代变量的生存期语义,并防止您看到捕获其值的副作用。
注意:上面的代码不等价于下面的LINQ表达式。
型
foreach示例生成一个
Func<int>
对象列表,所有对象都返回3。LINQ版本生成一个Func<int>
列表,它们分别返回1、2和3。这就是这种捕获风格难以移植的原因。5jdjgkvh3#
我认为这里最重要的是,为了避免语义上的混乱,你的代码应该只在它实际上是功能性的时候才是功能性的。换句话说,请不要在LINQ表达式中使用副作用。
l7mqbcuq4#
事实上,你的代码做了一些基本上非常实用的事情,即通过连接列表项将字符串列表减少到一个字符串。关于代码的唯一必要的事情是使用
StringBuilder
。实际上,函数式代码使这变得更容易,因为它不需要像你的代码那样特殊的情况。更好的是,.NET已经实现了这个特定的操作,并且可能比你的代码更有效1):
字符串
(Yes,调用
ToArray()
很烦人,但Join
是一个非常古老的方法,早于LINQ。当然,
Join
的“更好”版本可以这样使用:型
这个实现相当简单--但是再一次,使用
StringBuilder
(为了性能)使它变得势在必行。型
1)在没有查看反射器中的实现的情况下,我猜
String.Join
首先遍历字符串以确定总长度。这可以用于相应地初始化StringBuilder
,从而节省稍后昂贵的复制操作。EDIT by Slaks:以下是来自.Net 3.5的
String.Join
相关部分的参考源代码:型
xytpbqjk5#
你的问题中的特定循环可以像这样声明地完成:
字符串
至于性能,您可以预期性能下降,但这对大多数应用程序来说是可以接受的。
9o685dep6#
严格来说是的
任何
foreach
循环都可以通过使用ForEach
扩展方法转换为LINQ,例如MoreLinq中的方法。如果你只想使用“纯”LINQ(只使用内置的扩展方法),你可以滥用
Aggregate
扩展方法,如下所示:字符串
这将正确处理 * 任何 * foreach循环,甚至JaredPar的答案。EDIT:除非它使用
ref
/out
参数,不安全代码或yield return
。不要在真实的代码中使用这个技巧。
在您的特定情况下,您应该使用字符串
Join
扩展方法,例如:型
w51jfk4q7#
一般来说,你可以使用一个代表foreach循环主体的委托来编写一个lambda表达式,在你的例子中,类似于:
字符串
然后简单地在ForEach扩展方法中使用。这是否是一个好主意取决于主体的复杂性,如果它太大太复杂,除了可能的混乱之外,你可能不会从中获得任何东西;)