The Problem
The problem is that the ref
keyword will only affect the method it was declared. So, you would be able to change Main
's queue in One
's constructor, but not in the Produce
method.
In your code, One
is creating a second reference to the same queue object. The Produce
method is simply changing this second reference.
In other words, when you make a call to a method passing a parameter by reference, the called method will be able to change the referenced object, but only at this call site. After the call returns, whatever object is referenced by the _queue
variable at the Main
method will remain there.
One other consideration. The assignment at One
's constructor (where you commented "should be assigning by reference") works in exactly the same way as it would work if the ref
keyword wasn't there. Only if the assignment was inverted to queue = _queue;
then the ref
keyword would make a difference.
Solution A - Holder<T>
class
One solution that might make sense would be to create a Holder
class like this:
public class Holder<T> {
public T { get; set; }
}
Then, the One
class would work on a Holder<Queue<string>>
object. The Main
method would have to work on Holder<Queue<string>>
too. This way, One
could change the queue instance and it would be reflected in Main
.
Ok, ok. I know this solution is very awkward, but the requirements for your question seems awkward to me too. Is it a rhetorical question? Or are you trying to solve a bigger problem here? If it's the latter, I'm curious to know what is this bigger problem.
Solution B - pointers
Another solution would be to use pointers. It's perfectly possible to be done in C#, but not at all recommended. If you are interested, I can try to write a solution using pointers.
Solution C - Single position array
Your own answer gave me the idea for a third possible solution. It's intrinsically very similar to the other two solutions. Instead of explaining it in English, let me show it in C#.
class One
{
Queue<string>[] queueArray;
public One(Queue<string>[] queueArray)
{
if (queueArray == null) throw new ArgumentNullException("queueArray");
if (queueArray.Length != 1) throw new ArgumentException("queueArray must have one and only one item");
this.queueArray = queueArray;
}
public void Produce()
{
queueArray[0] = new Queue<string>();
queueArray[0].Enqueue("one");
}
}
class Program
{
static void Main(string[] args)
{
var queueArray = new Queue<string>[] { new Queue<string>() };
One one = new One(queueArray);
one.Produce();
string value = queueArray[0].Dequeue(); //this line sets "one" to value
}
}