Enumerable.Repeat 用于引用类型对象初始化

Enumerable.Repeat for reference type objects initialization

提问人:Michael 提问时间:7/6/2017 更新时间:5/30/2019 访问量:9052

问:

我有一个关于 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();

这将返回 true,如果我更改一个对象属性,所有其他对象也会更改它。

所以我的问题是:初始化引用类型对象是正确的方法吗?如果没有,那么什么是更好的方法?

C# 引用类型

评论


答:

31赞 Kapol 7/6/2017 #1

使用这种方式将只初始化一个对象,并在每次循环访问结果时返回该对象。Enumerable.Repeat

这些对象在内存中是否具有相同的地址?

只有一个对象。

要实现您想要的,您可以这样做:

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

这将返回一个包含 50 个不同对象的数组。A

顺便说一句,返回相同值的事实并不意味着对象在引用上是相等的(或者只是相等的)。两个不相等的对象可以具有相同的哈希代码。GetHashCode()

评论

0赞 Camilo Terevinto 7/6/2017
这很奇怪。我使用 Enumerable.Repeat 将对象复制几十次(因此我不必手动复制值),然后编辑我感兴趣的属性,它完美运行。所以,不太确定你说的“一个对象”是什么意思
1赞 Kapol 7/6/2017
来自 MSDN:“生成包含一个重复值的序列。 - 也许您使用的是值类型。在这种情况下,您每次都会得到一份副本。
0赞 Camilo Terevinto 7/6/2017
否,它们是同时具有 POCO 和嵌套类的 EF 实体
1赞 Kapol 7/6/2017
嗯。。。我刚刚对此进行了测试,并且按照我的假设工作:打印var x = Enumerable.Repeat(new C(), 2); Console.WriteLine(x[0] == x[1]);true
1赞 johnnyRose 7/6/2017
@CamiloTerevinto referencesource.microsoft.com/#System.Core/System/Linq/......Kapol 是正确的 - 它将返回相同的元素 n 次。
7赞 Enigmativity 7/6/2017 #2

为了帮助澄清 Camilo,这里有一些测试代码显示了手头的问题:

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.RepeatFoo

评论

0赞 Camilo Terevinto 7/6/2017
感谢您的测试。我将不得不重新访问执行此操作的代码,我可能忘记了某些事情
1赞 Enigmativity 7/6/2017
@CamiloTerevinto - 不用担心。我只是认为这值得澄清。
2赞 Gusty Abra 5/30/2019 #3

使用以下代码创建数组时:

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 循环来填充具有新引用类型的数组。