C # Indexer памяти вопрос - PullRequest
       20

C # Indexer памяти вопрос

2 голосов
/ 22 марта 2009

У меня есть следующий код внутри метода 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);
}

В представленном коде Рец [1] остается без изменений. Это связано с тем, что индексатор (который по-прежнему является специальным методом) возвратил копию структуры прямоугольника. В этом случае элементы были расположены на куче . Индексатор возвратил новую копию элемента, поместив новую копию в стек (поскольку Rectangle является типом значения).

Пока все хорошо ...

Позже я создал массив структур Rectangle в классе Program:

 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 ]

3 голосов
/ 22 марта 2009

Из этого вы заключаете, что индексатор в списке - это вызов метода, который помещает значение типа значения в стек при возврате из метода и что индексатор массива фактически транслируется в коде для вычисления смещения из начало массива и является прямой ссылкой на память.

0 голосов
/ 22 марта 2009

Как уже говорилось ранее, массивы - это особые вещи в CLI. У них нет индексатора. «Индексирование» в массиве непосредственно преобразуется в соответствующую команду CID ldelem.

0 голосов
/ 22 марта 2009

Насколько я знаю, «индексатор» для массивов на самом деле не индексатор. Массивы (или, скорее, тип Array) не могут рассматриваться как обычный тип в .NET Framework из-за его особой роли. (Чтобы привести другой пример, элементы массива ковариантны, что полезно во многих случаях, приводит к отклонениям по сравнению с другими типами). Он просто ссылается на n-й элемент массива, так что возвращаемый объект фактически является фактическим объектом, хранящимся в массиве. Просто относитесь к двум понятиям отдельно. Тот факт, что они имеют один и тот же синтаксис, на самом деле не имеет значения - есть некоторое сходство в функциональности, но не очень.

0 голосов
/ 22 марта 2009

Да. Индексатор массива представляет переменную, которую нужно изменить напрямую. Индексатор - это в основном метод с индексным параметром, к которому применен синтаксический сахар.

То же различие относится к полям и свойствам.

Если бы вы возвращали ссылочный тип из индексатора, это не имело бы большого значения, поскольку оно тем не менее ссылалось бы на тот же объект. Но когда вы возвращаете экземпляр struct (или любой тип значения в этом отношении), значение копируется, когда возвращается, и вы пытаетесь изменить копию, что в значительной степени бесполезно.

...