【问题标题】:Changing element value in List<T>.ForEach ForEach method更改 List<T>.ForEach ForEach 方法中的元素值
【发布时间】:2019-11-14 10:26:41
【问题描述】:

我有以下代码:

newsplit.ToList().ForEach(x => x = "WW");

我希望列表中的所有元素现在都是“WW”,但它们仍然是原始值。怎么来的?我必须做些什么不同的事情?

【问题讨论】:

    标签: c# linq c#-3.0


    【解决方案1】:

    假设newsplitIEnumerable&lt;string&gt;,你想要:

    newsplit = newsplit.Select(x => "WW");
    

    您当前拥有的代码相当于以下代码:

    foreach(string x in newsplit.ToList()) {
        AssignmentAction(x);
    }
    
    ...
    
    public static void AssignmentAction(string x) {
        x = "WW";
    }
    

    由于 C# 的按值传递语义和字符串的不变性,此方法不会修改 x

    【讨论】:

    • 是字符串数组还是在我的情况下是 List IEnumerable,因为我认为它不是?
    • @Jon: arrays 和 List 都支持 IEnumerable 接口
    • 我不认为 Select() 是 Jon 想要的,听起来他想修改 IEnumerable 本身。选择只会给他已经是“WW”的项目
    • @AgileJon:听起来你在混淆 IEnumerable.Where 和 IEnumerable.Select.
    • @Downvoters:两个反对票?这是错的吗?这有害吗?我忽略了什么?
    【解决方案2】:

    其他答案已经解释了为什么您当前的代码不起作用。这是一个可以修复它的扩展方法:

    // Must be in a static non-nested class
    public static void ModifyEach<T>(this IList<T> source,
                                     Func<T,T> projection)
    {
        for (int i = 0; i < source.Count; i++)
        {
            source[i] = projection(source[i]);
        }
    }
    

    然后像这样使用:

    newsplit.ModifyEach(x => "WW");
    

    这适用于IList&lt;T&gt; 的任何实现,例如数组和List&lt;T&gt;。如果您需要它与任意 IEnumerable&lt;T&gt; 一起工作,那么您就有问题了,因为序列本身可能不可变。

    当然,使用Select() 是一种更实用的方法,但有时改变现有集合值得做的...

    【讨论】:

    • @Jon:我认为您的第二个代码块中的意思是 newsplit.ToList().ModifyEach(x => "WW")?
    • @Jason: 几乎...但是如果您调用 ToList() 但不保留对该新列表的引用,则不会保留修改。特别是它不会修改原始集合。已针对预期用途编辑答案。
    • @Jon:同意。感谢您的澄清。
    【解决方案3】:

    ForEach 将允许您操作 IEnumerable 的元素,但不会更改元素的引用。

    即,这会将 IEnumerable 中每个元素的 Foo 属性设置为字符串 "WW"

    newsplit.ToList().ForEach(x => x.Foo = "WW");
    

    但是,您将无法修改 IEnumerable 本身的值。

    【讨论】:

    • 至少在 VB.Net 中我只能在 ForEach 中分配元素的属性,如果多行 ForEach,Linq ForEach 不会通过引用分配。
    【解决方案4】:

    这是因为 LINQ 表达式正在创建 Anonymous Types,而这些是只读的。他们不能被分配到。此外,在每个循环的标准中,您不能将其分配给正在枚举的集合。试试:

        foreach (var item in newsplit)
        {
            item = "this won't work";
        }
    

    【讨论】:

    • 在给定的 ForEach 表达式中没有创建匿名类型。参数是一个delegate,应用于迭代中的每个元素;当然,由于您给出的原因,它不会起作用。
    • 你是对的,当然——不知道我在想什么!但是第二部分,关于集合在迭代时是不可变的,值得注意。谢谢。
    【解决方案5】:

    你可以这样写:

    newsplit = newsplit.Select(x => "WW").ToList();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-19
      • 2010-11-08
      • 1970-01-01
      • 2011-10-22
      • 2016-08-27
      • 2020-08-22
      • 2016-02-22
      • 1970-01-01
      相关资源
      最近更新 更多