1

I have a Queue<object> that I push objects into but if I modify the object after I put it in the queue, the object in the queue also changes.

For example

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

If I then go look in the queue, object1 will equal 0, not 1 like when I put it in... suggestions?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
that_guy
  • 2,313
  • 4
  • 33
  • 46

4 Answers4

2

Your queue is a queue of references to objects, not values of the object. Either clone the object and modify the cloned object when not working in the queue or don't modify the object after putting it in the queue.

Consider an analogy for further explanation. Imagine you have to keep track of 100 paintings. You choose to use a queue to keep track of all the paintings. You have two options to store the paintings in your queue:

  1. Pickup each paintings and move it into the queue
  2. Store the location of each paintings in your queue

Well option 1 is difficult because paintings are heavy are really big. Option 2 is much easier because all you need is a simple reference to each painting. However, with option 2, anyone can change the painting without going through the queue because the painting isn't actually in the queue. Option 1 is called pass by value. Option 2 is called pass by reference. And that is how C# stores objects in a queue.

Note: this analogy is imperfect, but it should help you understand what's happening.

The following code should help solve your problem:

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

MemberwiseClone

Alternatively, you could store your information with value types (int, char, bool, struct, etc) if you are storing simple and small information. Value types are stored in queues with option one (pass by value)

int a = 1;
var myQueue = new Queue<int>();
myQueue.Enqueue(a);
a = 2;
//Prints 1
Console.WriteLine(myQueue.First());
//Prints 2
Console.WriteLine(a);
Steven Wexler
  • 16,589
  • 8
  • 53
  • 80
2

The other answers are correct in a technical sense, but what I'd be asking myself is "Why am I changing queued objects in the first place?". Typically you put something on a queue so it goes somewhere else for further processing. If you subsequently change it, what actaully are you sending and what actually are you working with? Something that's the original object or something that's like the object but not quite? What are the differences and are they important? Which is the correct copy/version?

How do you reconcile the changes you make with the outcome on the other side of the queue?

If you can't then your process is flawed. If you can then it probably doesn't matter if you change the object anyway (unlikely to be the case).

Seems to me like you may have either too much on the queue and your object needs breaking down and/or a process problem.

LoztInSpace
  • 5,584
  • 1
  • 15
  • 27
1

In C#, objects are usually passed by references unless otherwise specified. You could to clone the objects before putting them in the queue, then when you change the original copy, the ones in the queue will not be changed.

One of many ways to achieve this is doing something like this:

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

Then in the object's copy constructor, do a member wise deep copy:

class myClass
{
    public int i;
    public Object (Object object1)
    {
        this.i = object1.i;
    }
}
TelKitty
  • 3,146
  • 3
  • 18
  • 21
  • What do I have to do to get the .Clone() property on my object? (custom object) include a reference? – that_guy May 17 '13 at 05:15
  • It is bad practice to implement IClonable. This question explains why. http://stackoverflow.com/questions/3712449/what-is-the-use-of-iclonable-interface-in-net. – Steven Wexler May 17 '13 at 05:26
  • @that_guy read my modified answer. [Object.MemberwiseClone](http://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspx) Method returns a shallow copy too, you need a deep copy. – TelKitty May 17 '13 at 05:43
0

All really good answers, after searching around a bit, it seems that using a copy constructor is the simplest way to go about this and everything seems to be working properly now. Saw on this post: https://stackoverflow.com/a/78577/1174574

Thoughts?

Community
  • 1
  • 1
that_guy
  • 2,313
  • 4
  • 33
  • 46
  • 1
    Seems reasonable. Both are similar. Both have small trade-offs. You should be good as long as you clone your objects correctly and clearly show whether you're making a deep or shallow copy. – Steven Wexler May 17 '13 at 05:45
  • See my "answer". Now you know how, make sure you should. – LoztInSpace May 17 '13 at 06:07