Enumerable.Repeat for reference type objects initialization
Asked Answered
E

3

21

I have a question about Enumerable.Repeat function.

If I will have a class:

class A
{
//code
}

And I will create an array, of that type objects:

A [] arr = new A[50];

And next, I will want to initialize those objects, calling Enumerable.Repeat:

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

Will those objects have the same address in memory? If I will want to check their hash code, for example in that way:

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

This will return me true, and if I will change one object properties, all other objects will change it too.

So my question is: is that properly way, to initialize reference type objects? If not, then what is a better way?

Evelunn answered 5/7, 2017 at 22:24 Comment(0)
A
32

Using Enumerable.Repeat this way will initialize only one object and return that object every time when you iterate over the result.

Will those objects have the same address in memory?

There is only one object.

To achieve what you want, you can do this:

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

This will return an array of 50 distinct objects of type A.

By the way, the fact that GetHashCode() returns the same value does not imply that the objects are referentially equal (or simply equal, for that matter). Two non-equal objects can have the same hash code.

Agenda answered 5/7, 2017 at 22:35 Comment(6)
That's weird. I use Enumerable.Repeat to copy an object some dozens of times (so I don't have to copy the values manually) and then edit the properties I'm interested in, and it works flawlessly. So, not really sure what you mean by "one object"Tilney
From MSDN: "Generates a sequence that contains one repeated value." - Maybe you were using value types. In that case you would get a copy every single time.Agenda
No, they are EF entities with both POCO and nested classesTilney
Hmm... I have just tested this and works as I assumed: var x = Enumerable.Repeat(new C(), 2); Console.WriteLine(x[0] == x[1]); prints trueAgenda
@CamiloTerevinto referencesource.microsoft.com/#System.Core/System/Linq/… Kapol is correct - it will return the same element n times.Exsert
@CamiloTerevinto - I've put an answer to show that only one instance is created: https://mcmap.net/q/32985/-enumerable-repeat-for-reference-type-objects-initializationShellbark
S
7

Just to help clarify for Camilo, here's some test code that shows the issue at hand:

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;
}

This prints "Jill". Thus it shows that Enumerable.Repeat is only creating one instance of the Foo class.

Shellbark answered 6/7, 2017 at 0:11 Comment(2)
Thanks for the test. I'll have to revisit the code that does this, I'm probably forgetting about somethingTilney
@CamiloTerevinto - No worries. I just thought that this was worth clarifying.Shellbark
H
3

When using the following code to create an array:

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

The reason why each location in the array is the same is because you are passing an object, and not a function that creates an object, the code above is the same as:

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

The reason above also explains why using a Select statement, like in the code below, creates a new object for each entry, because you are passing a function that dictates how each object is created, rather than the object itself.

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

I would use a simple for loop to populate an array with new reference types.

Humanity answered 30/5, 2019 at 15:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.