【问题标题】:Unable to reassign values in a linq statement [duplicate]无法在 linq 语句中重新分配值 [重复]
【发布时间】:2017-03-18 11:27:10
【问题描述】:

我正在尝试对 int 类型列表中的所有数字求平方。但是,当我运行代码时,列表似乎根本没有改变。

public static List<int> SquareList(List<int> root)
{
    root.ForEach(x => x = x*x);
    return root;
}

x_unit 中的测试类。

[Fact]
public void testSqures()
{
    var input = new List<int> { 1, 2, 3 };
    var expected = new List<int> { 1, 4, 9 };
    var result = Square.SquareList(input);

    Assert.Equal(expected,result);
}

问题foreach 操作符不会改变底层对象吗?

我需要创建一个新列表吗?还是有办法将列表转换到位?

【问题讨论】:

  • 来自 MSDN:不支持修改 Action&lt;T&gt; 委托主体中的基础集合,并导致未定义的行为。
  • 您正在使用值类型,并且无法在 Action 委托中更新值类型。您肯定需要创建一个新列表。

标签: c# linq


【解决方案1】:

改成

return root.Select(x => x*x).ToList();

这不会改变现有列表,它会创建一个新列表并返回它是首选的。如果您确实想更新原始列表,请更改签名以传入ref,然后更新指向新列表的指针。

public static List<int> SquareList(ref List<int> root)
{
    root = root.Select(x => x*x).ToList();
    return root;
}

或将其与 for 循环一起使用

public static List<int> SquareList(List<int> root)
{
    for(int i = 0; i < root.Count; i++)
        root[i] = root[i]*root[i];
    return root;
}

ForEach 确实会遍历列表,如果您有一个包含 int 的引用类型(类),您可以更改该类型内部的值,但您不能重新分配列表中包含的指针。

【讨论】:

    【解决方案2】:

    如果您想获得集合的新表示,请使用 Select 而不是 ForEach。返回新对象而不是更改它是函数式编程的一种范式。 LINQ 有助于使用这种范例。

    【讨论】:

      【解决方案3】:

      来自 MSDN:

      不支持修改 Action 委托主体中的基础集合,这会导致未定义的行为。

      您应该只使用常规的for 循环来执行此类操作,而不是使用 LINQ 或类似的函数语句

      public static List<int> SquareList(List<int> root)
      {
          for (int i = 0, n = root.Count; i < n; ++i)
              root[i] = root[i] * root[i];
          return root;
      }
      

      【讨论】:

      • 您引用的文档与问题无关。警告是指对集合结构的修改,即删除或插入/添加元素,而不是简单地替换值。
      • @PeterDuniho 恕我直言,您是否有任何带有 ValueType 的官方文档或代码示例来证明您的观点?我认为您对 Modifying the underlying collectionModifying the values referred to by the underlying collection 这两个术语感到困惑
      • 如果您尝试修改集合,则会抛出InvalidOperationException,并显示消息“集合已修改;枚举操作可能无法执行。”。这与尝试修改本身实际上不是集合的一部分的值类型完全不同。代码示例:List&lt;int&gt; values = new List&lt;int&gt; { 0, 1, 2 }; values.ForEach(i =&gt; values[i] = i + 1);,抛出异常。 ForEach() 不应该用于修改列表是正确的,但引用文档的特定部分是不正确的,因为它与 OP 的代码无关。
      • @PeterDuniho 您的代码示例支持我所说的。这里似乎没有人在谈论attempting to modify a value type that itself is not actually part of the collectionList&lt;int&gt; 是引用类型,int 是值类型,我们正在讨论在容器List&lt;int&gt;(引用类型)中修改包含int(值类型)的内容。在这个主题上我没有任何进一步的 cmets 可做
      • OP 正在用x*x 替换传递给他的Action&lt;int&gt; 代表的x 中存储的值。这对原始集合没有影响,因此 MSDN 中的警告不适用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-05
      • 1970-01-01
      • 2012-03-11
      • 1970-01-01
      相关资源
      最近更新 更多