1

我有一个Queue<object>将对象推送到其中的对象,但是如果在将对象放入队列后对其进行修改,则队列中的对象也会更改。

例如

object1 = 1;
queue.Enqueue(object1);
object1 = 0;

如果我然后去查看队列,object1 将等于 0,而不是像我将它放入时那样的 1... 建议?

4

4 回答 4

2

您的队列是对对象的引用队列,而不是对象的值。克隆对象并在不在队列中工作时修改克隆的对象,或者在将对象放入队列后不修改。

考虑一个类比来进一步解释。想象一下,您必须跟踪 100 幅画作。您选择使用队列来跟踪所有画作。您有两种选择将绘画存储在队列中:

  1. 拿起每幅画并将其移入队列
  2. 将每幅画的位置存储在队列中

好吧,选项 1 很困难,因为画很重,真的很大。选项 2 更容易,因为您所需要的只是对每幅画的简单引用。但是,使用选项 2,任何人都可以在不经过队列的情况下更改绘画,因为绘画实际上不在队列中。选项 1 称为按值传递。选项 2 称为按引用传递。这就是 C# 将对象存储在队列中的方式。

注意:这个类比是不完美的,但它应该可以帮助你理解正在发生的事情。

以下代码应该有助于解决您的问题:

object1 = 1;
queue.Enqueue(object1);
//Clone is a method you'll need to create on the class
//C# provides a MemberwiseClone method that should be very helpful
object2 = object1.Clone();
object2 = 2

会员克隆

或者,如果您要存储简单而小的信息,您可以使用值类型(int、char、bool、struct 等)存储您的信息。值类型存储在具有选项一的队列中(按值传递)

int a = 1;
var myQueue = new Queue<int>();
myQueue.Enqueue(a);
a = 2;
//Prints 1
Console.WriteLine(myQueue.First());
//Prints 2
Console.WriteLine(a);
于 2013-05-17T05:05:49.723 回答
2

其他答案在技术意义上是正确的,但我要问自己的是“为什么我首先要更改排队的对象?”。通常,您将某些内容放在队列中,以便将其放到其他地方进行进一步处理。如果您随后更改它,您发送的实际是什么以及您实际使用的是什么?是原始对象的东西还是类似于对象但不完全一样的东西?有什么区别,它们是否重要?哪个是正确的副本/版本?

您如何协调您所做的更改与队列另一端的结果?

如果你不能,那么你的过程就有缺陷。如果可以,那么无论如何更改对象可能都没有关系(不太可能是这种情况)。

在我看来,您的队列可能太多,您的对象需要分解和/或流程问题。

于 2013-05-17T05:31:28.717 回答
1

在 C# 中,除非另有说明,否则对象通常通过引用传递。您可以在将对象放入队列之前克隆对象,然后当您更改原始副本时,队列中的对象不会更改。

实现这一目标的众多方法之一是执行以下操作:

object1 = 1;
queue.Enqueue(new Object(object1));
object1 = 0;

然后在对象的复制构造函数中,进行成员明智的深度复制:

class myClass
{
    public int i;
    public Object (Object object1)
    {
        this.i = object1.i;
    }
}
于 2013-05-17T05:06:45.900 回答
0

所有非常好的答案,经过一番搜索,似乎使用复制构造函数是解决这个问题的最简单方法,现在一切似乎都正常工作。看到这篇文章:https ://stackoverflow.com/a/78577/1174574

想法?

于 2013-05-17T05:37:08.247 回答