尝试分配给 C#“foreach 迭代变量”会生成编译时错误。在 Linq [IEnumerable].ForEach(...) 中这样做则不会。为什么?

cpr*_*leg 1 c# linq foreach runtime

今天,当我尝试使类变得更整洁并删除用于初始化字符串数组的 for 循环时,我注意到了我认为 C# 和 Linq 中的奇怪行为。

我原来的代码:

    for(int i = 0; i < tagCount; i++)
    {
        myObj.tags[i] = string.Empty;
    }
Run Code Online (Sandbox Code Playgroud)

众所周知,不能为 C# foreach 循环中的迭代变量赋值。例如,以下代码会生成编译时错误(其中 myObj 是一个对象,其中包含名为“tags”的字符串数组):

    foreach(string s in myObj.tags)
    {
        s = string.Empty;
    }

    Gives: "Cannot assign to 's' because it is a 'foreach iteration variable'"
Run Code Online (Sandbox Code Playgroud)

但执行以下操作可以正确编译:

    myObj.tags.ToList().ForEach(s => s = string.Empty);
Run Code Online (Sandbox Code Playgroud)

我的问题是为什么这个语法编译没有任何问题?


注意:奇怪的行为 - 可能是错误?- 以下

作为后续,我认为确实值得注意的是,虽然 Linq 方法编译,但在运行时,s=string.Empty看不到命令​​的效果,也不会生成运行时错误。string.Empty可以替换为任何值,并且检查数组中的任何索引都myObj.tags将显示空值。突破并步入...ForEach(s=>s=string.Empty)显示该行正在按预期执行,但 s 的值没有变化。

这让我觉得很奇怪,主要是因为也没有生成错误——它似乎什么也没做。这是设计使然吗?疏忽?

感谢大家的意见。


(PS,我知道 ToList().ForEach() 的性能影响。我只是想看看是否可以删除该 for 循环。我现在对编译和运行时表现出的行为背后的原因更感兴趣)。

Jon*_*eet 5

是的,它什么也没做 - 但在 C# 中很多情况下都会发生这种情况。目前尚不清楚您期望它在哪里出现错误,或者您期望它实现什么目标。基本上,您的 lambda 表达式是编写如下方法的简写:

static void Foo(string s)
{
    s = string.Empty;
}
Run Code Online (Sandbox Code Playgroud)

这不是一种有用的方法,但却是一种完全有效的方法。为列表中的每个值调用它并不会使它变得更有用。

分配回值参数(而不是refout参数)并且不再从参数读取基本上是没有意义的,但有效。

在删除循环方面 - 您可以做的一件事是编写一个扩展方法:

public static void ReplaceAll<T>(this IList<T> list, T value)
{
    // TODO: Validation
    for (int i = 0; i < list.Count; i++)
    {
        list[i] = value;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以打电话:

myObj.tags.ReplaceAll("");
Run Code Online (Sandbox Code Playgroud)