Enumerable.Repeat для инициализации объектов ссылочного типа

У меня вопрос по функции Enumerable.Repeat.

Если у меня будет класс:

class A
{
//code
}

И я создам массив объектов этого типа:

A [] arr = new A[50];

Затем я хочу инициализировать эти объекты, вызывая Enumerable.Repeat:

arr = Enumerable.Repeat(new A(), 50);

Будут ли эти объекты иметь одинаковый адрес в памяти? Если я захочу проверить их хэш-код, например, таким образом:

bool theSameHashCode = questions[0].GetHashCode() == questions[1].GetHashCode();

Это вернет мне истину, и если я изменю свойства одного объекта, все остальные объекты тоже изменят его.

Итак, мой вопрос: правильно ли это инициализировать объекты ссылочного типа? Если нет, то какой способ лучше?


person Michael    schedule 05.07.2017    source источник


Ответы (3)


Использование Enumerable.Repeat таким образом инициализирует только один объект и будет возвращать этот объект каждый раз, когда вы перебираете результат.

Будут ли эти объекты иметь одинаковый адрес в памяти?

Есть только один объект.

Чтобы добиться желаемого, вы можете сделать это:

Enumerable.Range(1, 50).Select(i => new A()).ToArray();

Это вернет массив из 50 различных объектов типа A.

Кстати, тот факт, что GetHashCode() возвращает одно и то же значение, не означает, что объекты ссылочно равны (или просто равны, если на то пошло). Два неравных объекта могут иметь один и тот же хэш-код.

person Kapol    schedule 05.07.2017
comment
Это странно. Я использую Enumerable.Repeat для копирования объекта несколько десятков раз (поэтому мне не нужно копировать значения вручную), а затем редактирую свойства, которые меня интересуют, и он работает безупречно. Итак, не совсем уверен, что вы подразумеваете под одним объектом - person Camilo Terevinto; 06.07.2017
comment
Из MSDN: генерирует последовательность, содержащую одно повторяющееся значение. - Возможно, вы использовали ценностные типы. В этом случае вы будете получать копию каждый раз. - person Kapol; 06.07.2017
comment
Нет, это сущности EF с POCO и вложенными классами. - person Camilo Terevinto; 06.07.2017
comment
Хм ... Я только что проверил это и работает так, как я предполагал: var x = Enumerable.Repeat(new C(), 2); Console.WriteLine(x[0] == x[1]); печатает true - person Kapol; 06.07.2017
comment
@CamiloTerevinto referenceource.microsoft.com/#System.Core/ System / Linq / Капол прав - он вернет один и тот же элемент n раз. - person johnnyRose; 06.07.2017
comment
@CamiloTerevinto - я поставил ответ, чтобы показать, что создается только один экземпляр: stackoverflow.com/a/44937849/259769 - person Enigmativity; 06.07.2017

Чтобы прояснить ситуацию для Камило, вот тестовый код, который показывает проблему:

void Main()
{
    var foos = Enumerable.Repeat(new Foo(), 2).ToArray();
    foos[0].Name = "Jack";
    foos[1].Name = "Jill";
    Console.WriteLine(foos[0].Name);    
}

public class Foo
{
    public string Name;
}

Это печатает «Джилл». Таким образом, это показывает, что Enumerable.Repeat создает только один экземпляр класса Foo.

person Enigmativity    schedule 06.07.2017
comment
Спасибо за тест. Придется пересмотреть код, который это делает, наверное, я что-то забываю - person Camilo Terevinto; 06.07.2017
comment
@CamiloTerevinto - Не беспокойтесь. Я просто подумал, что это стоит уточнить. - person Enigmativity; 06.07.2017

При использовании следующего кода для создания массива:

var foos = Enumerable.Repeat(new Foo(), 2).ToArray();

Причина, по которой каждое место в массиве одинаково, заключается в том, что вы передаете объект, а не функцию, которая создает объект, приведенный выше код такой же, как:

var foo = new Foo();
var foos = Enumerable.Repeat(foo , 2).ToArray();

Приведенная выше причина также объясняет, почему использование оператора Select, как в приведенном ниже коде, создает новый объект для каждой записи, потому что вы передаете функцию, которая определяет, как создается каждый объект, а не сам объект.

Enumerable.Range(1, 2).Select(i => new Foo()).ToArray();

Я бы использовал простой цикл for для заполнения массива новыми ссылочными типами.

person Gusty Abra    schedule 30.05.2019