2

我在 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(仍然是一种特殊方法)返回了矩形结构的副本。在这种情况下,元素位于heap上。索引器通过将新副本放在堆栈上返回元素的新副本(因为 Rectangle 是值类型)。

到现在为止还挺好...

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

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

在主要方法中:

Program p = new Program();

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

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

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

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

亲切的问候 PK

4

4 回答 4

3

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

于 2009-03-22T14:43:52.113 回答
0

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

同样的差异也适用于字段和属性。

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

于 2009-03-22T14:41:53.447 回答
0

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

于 2009-03-22T14:42:17.093 回答
0

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

于 2009-03-22T16:32:02.667 回答