【问题标题】:C# Indexer memory questionC# Indexer 内存问题
【发布时间】:2010-10-14 20:10:59
【问题描述】:

我在 main 方法中有以下代码:

List<Rectangle> rects = new List<Rectangle>();

for (int i = 0; i < 5; i++)
{
    rects.Add(new Rectangle(1, 1, 1, 1));
}

foreach (Rectangle item in rects)
{
    Console.WriteLine(item);
}

rects[1].Inflate(100, 100);

foreach (Rectangle item in rects)
{
    Console.WriteLine(item);
}

在呈现的代码中,rects[1] 保持不变。这是因为 indexer(仍然是一个特殊的方法)返回了矩形结构的 copy。在这种情况下,元素位于 heap 上。索引器通过将新的 copy 放在堆栈上返回元素的新 copy(因为 Rectangle 是值类型)。

到目前为止一切都很好......

后来我在 Program 类中创建了一个 Rectangle 结构数组:

 Rectangle[] rect = new Rectangle[] { new Rectangle(1, 1, 1, 1), new Rectangle(1, 1, 1, 1) };

在main方法中:

Program p = new Program();

p.rect[1].Inflate(100, 100);

foreach (var item in p.rect)
{
    Console.WriteLine(item);
}

我希望 rect 数组的索引器也返回矩形结构的 副本,但这次更改了原始元素(也位于 上) .

这是为什么呢?数组索引器是否以不同的方式工作?

亲切的问候 PK

【问题讨论】:

    标签: c# stack heap-memory indexer


    【解决方案1】:

    如前所述,数组是 CLI 中的特殊事物。他们没有索引器。数组中的“索引”直接转换为适当的 ldelem CIL 指令。

    【讨论】:

      【解决方案2】:

      由此您可以得出结论,列表上的索引器是一个方法调用,它在从方法返回时将值类型的值放在堆栈上,并且数组索引器实际上在代码中转换为计算偏移量数组的开头,是直接的内存引用。

      【讨论】:

      • 说得好。如果您在示例中尝试,您可以更清楚地看到相同的差异 { rects[1].X = 100; } - 我相信不会编译,而不是 { p.rect[1].X = 100; } 这将编译和工作。
      【解决方案3】:

      据我所知,数组的“索引器”并不是真正的索引器。数组(或者更确切地说是 Array 类型)在 .NET Framework 中不能被视为普通类型,因为它的特殊作用。 (再举一个例子,数组项是协变的,与其他类型相比,这在许多情况下有助于导致异常)。它只是引用数组的第 n 个元素,因此它返回的对象实际上是存储在数组中的实际对象。只需分别对待这两个概念。它们具有相同语法的事实在这里并不真正相关 - 功能上有一些相似之处,但不多。

      【讨论】:

        【解决方案4】:

        是的。数组索引器表示要直接更改的变量。索引器基本上是一种带有索引参数的方法,并应用了语法糖。

        同样的区别也适用于字段和属性。

        如果你从索引器返回一个引用类型,它不会有太大的不同,因为它仍然会引用同一个对象。但是,当您返回 struct 实例(或任何值类型)时,该值会在返回时被复制,而您试图修改副本,这几乎没有用。

        【讨论】:

        • 出于同样的原因,你不能做像myWindowsForm.Location.X++;这样的事情。
        猜你喜欢
        • 2010-11-05
        • 1970-01-01
        • 1970-01-01
        • 2011-07-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多