【问题标题】:C# - Tuple arrays are mutable, but tuple lists are not. How do I get around this?C# - 元组数组是可变的,但元组列表不是。我该如何解决这个问题?
【发布时间】:2021-01-10 21:52:42
【问题描述】:

我有一个要修改的值对数组。我还需要从这个数组中添加和删除值,所以我使用了一个列表。当我尝试使用列表时,我遇到了错误。

Error CS1612 - Cannot modify the return value of 'List<(int, float)>.this[int]' because it is not a variable

所以我决定进行调查。我尝试改用数组,它......工作正常吗?以下代码仅在arr1[0].Item1 += 1; 上引发错误。

static void Main()
    {
        List<(int, float)> arr1 = new List<(int, float)>() { (0, 0) };
        (int, float)[] arr2 = new (int, float)[1];

        arr1[0].Item1 += 1; // This line
        arr2[0].Item1 += 1;
    }

为什么元组数组是可变的,而列表不是?这是因为数组是简单的数据块,您可以轻松修改,但列表背后有很多后端使事情变得复杂?有没有一种简单的方法来解决这个问题,还是我必须制作自己的自定义类?

【问题讨论】:

  • C# 数组的特殊之处在于,访问其中的元素会为您提供对该元素的 引用,而 List 的索引器会返回一个副本
  • @UnholySheep:我会避免在这里使用术语“引用”——它已经是一个重载的术语,对值类型的“引用”最终听起来有点奇怪。我认为将数组视为变量的集合更清楚。

标签: arrays list tuples c#-7.0


【解决方案1】:

为什么元组数组是可变的,而列表不是?

列表本身是可变的,但不是按照您的方式。请注意,这不是特定于元组的任何东西 - any 可变结构就是这种情况。

列表索引器 getter 返回一个 (即您的情况下的元组副本) - 因此修改该值不会修改列表中的副本。编译器试图避免您对即将被丢弃的值进行更改。数组访问不会 这样做 - arr2[0] 指的是数组中的变量。 (数组实际上是变量的集合。)

如果你想改变列表,你必须获取元组,改变它,然后放回去:

var tuple = arr1[0];
tuple.Item1++;
arr1[0] = tuple;

请注意,这也解释了为什么您不能将列表访问表达式用作 ref 参数的参数,但您可以对数组执行等效操作:

public void Method(ref int x) => x++;

public void CallMethod()
{
    var list = new List<int> { 0 };
    var array = new int[] { 0 };
    Method(ref list[0]); // Error
    Method(ref array[0]); // Valid
}

【讨论】:

  • 很可能只是因为 ref returns 在引入 IList&lt;T&gt;List&lt;T&gt; 时在 C# 中不存在。如果是,那么就不会有这种差异,现在必须永远保持这种差异以实现向后兼容性。
  • @IvanStoev:嗯……也许吧。 IReadOnlyList&lt;T&gt; 能够使用 ref 返回,这会在它们之间引入奇怪的不一致。 (我怀疑还有一些更微妙的地方 - 当一个数组由于列表扩展而被复制时,如果你仍然有一个 ref 到“旧”数组,那可能会产生一些非常意想不到的行为。基本上我不认为这是一个灌篮......)
猜你喜欢
  • 2021-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-13
  • 2020-06-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多