1

我有一个放入 a 的结构List<T>,我想在该结构中的特定位置编辑一些值。如果不复制结构、编辑副本和替换列表中的条目,这是否可能?

4

3 回答 3

2

不,要做到这一点,您需要引用List/未提供的内部数组元素IList

如果必须,您可以使用不安全的代码和数组来做到这一点。

于 2012-11-21T01:08:25.140 回答
1

来自 J.Richter 的“CLR via C#”,第 3 版:

值类型应该是不可变的:也就是说,它们不应该定义任何修改任何类型的实例字段的成员。事实上,我建议将值类型的字段标记为只读,以便在您不小心编写尝试修改字段的方法时编译器会发出错误。

...

请记住,值类型和引用类型具有非常不同的行为,具体取决于它们的使用方式。


考虑这段代码:

public interface IChangeStruct
{
    int Value { get; }
    void Change(int value);
}

public struct MyStruct : IChangeStruct
{
    int value;

    public MyStruct(int _value)
    {
        value = _value;
    }

    public int Value
    {
        get
        {
            return value;
        }
    }

    public void Change(int value)
    {
        this.value = value;
    }
}

它的用法:

static void Main(string[] args)
{
    MyStruct[] l = new MyStruct[]
        {
            new MyStruct(0)
        };
    Console.WriteLine(l[0].Value);
    l[0].Change(10);
    Console.WriteLine(l[0].Value);

    Console.ReadLine();
}

输出是:

0 10

所以它可以满足您的需求。

但是,这同样不适用于List<T>. 我猜是Alexei Levenkov提到的原因。因此,我强烈建议您更改structclass如果所讨论的类型不是每个实例不可变的。

于 2012-11-21T01:20:46.907 回答
1

您最好的选择可能是让您的结构直接公开其字段,然后使用如下代码:

  var temp = myList[3];
  温度.X += 4;
  我的列表 [3] = 温度;

我认为 .net 未能提供任何更新列表项的方法是 .net 的一个重大弱点,但在希望表示不应“附加”到任何其他此类组的一小组正交值(例如点中的坐标,矩形的原点和大小等)。结构应该是“不可变”的概念已被重复为咒语很长一段时间,但这并不意味着它是好的建议。这样的概念主要源于两件事:

  1. 在其构造函数之外的任何成员中修改 `this` 的结构是古怪的。这种怪癖过去(并且在某种程度上仍然如此)适用于属性设置器,但不适用于直接公开其字段的结构。因为微软将所有结构字段都包装在属性中,这意味着虽然可变结构如果暴露了字段就可以具有合理的语义,但它们最终会产生古怪的语义。微软随后将古怪的语义归咎于结构是可变的这一事实,而不是不必要地用属性包装字段。
  2. 有些人喜欢将 .net 建模为只有一种对象,而不是将值类型和引用类型作为不同类型的实体。所谓的“不可变”值类型的行为与引用类型的行为非常接近,以至于它们可以假装它们是同一事物,而易于可变的值类型的行为则大不相同。实际上,理解暴露字段值类型的行为比理解所谓的“不可变”值类型与引用类型行为不同的所有极端情况更容易,如果不理解前者,就不可能理解后者。请注意,虽然值类型可能假装是不可变的,但实际上不存在不可变值类型这样的东西。

实际上,如果一个类型应该代表一小组正交值,那么暴露字段结构是完美的选择。即使必须使用上面显示的笨重代码来更新 a 中项目的字段List<structType>,它也比使用类类型或所谓的“不可变”结构的任何替代方法要好。知道这myList是一个带有暴露字段的结构X就足以完全理解上面的代码。如果使用类或“不可变”结构,唯一的远程选择是myList[3] = myList[3].WithX(myList[3].X + 4);,但这需要相关类型提供WithX方法(并且可能是WithWhatever()每个字段的方法)。这样的方法将增加许多倍的代码量,人们必须阅读以确定一个方法实际上会做什么(人们可能期望WithX将返回一个与旧实例相同的新实例,除了 的值X,但是在阅读所有涉及的代码之前,人们不会知道;相比之下,知道这X是结构类型的公开字段就足以知道上面的代码会做什么。

于 2012-11-21T18:40:12.157 回答