Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is list when passed without ref to a function acting like passed with ref?

If I did not get this terribly wrong, this behaviour is strange for me. Rather than explaining, I'll post a sample code below and please tell me why does I get output x and not y.

    private void button1_Click(object sender, EventArgs e)
    {
        List<int> l = new List<int>() { 1, 2, 3 };
        Fuss(l);
        MessageBox.Show(l.Count.ToString());
    }

    private void Fuss(List<int> l)
    {
        l.Add(4);
        l.Add(5);
    }

Output should, I assume would be 3. But I get the output as 5. I understand the output can be 5 if I do this:

    private void button1_Click(object sender, EventArgs e)
    {
        List<int> l = new List<int>() { 1, 2, 3 };
        Fuss(ref l);
        MessageBox.Show(l.Count.ToString());
    }

    private void Fuss(ref List<int> l)
    {
        l.Add(4);
        l.Add(5);
    }
like image 925
nawfal Avatar asked Sep 06 '11 14:09

nawfal


People also ask

Are lists always passed by reference in C#?

List<T> is a class, and all class instances are passed by reference.

Why are objects passed by reference?

Object references are passed by value The reason is that Java object variables are simply references that point to real objects in the memory heap. Therefore, even though Java passes parameters to methods by value, if the variable points to an object reference, the real object will also be changed.

Are Java lists passed by reference?

Yes, a List that you pass to a method is passed by reference. Any objects you add to the List inside the method will still be in the List after the method returns.

What is the point of ref in C#?

The ref keyword in C# is used for passing or returning references of values to or from Methods. Basically, it means that any change made to a value that is passed by reference will reflect this change since you are modifying the value at the address and not just the value.


2 Answers

Parameters are passed by value in C# unless they are marked with the ref or out modifiers. For reference types, this means that the reference is passed by value. Therefore, in Fuss, l is referring to the same instance of List<int> as its caller. Therefore, any modifications to this instance of List<int> will be seen by the caller.

Now, if you mark the parameter l with ref or out, then the parameter is passed by reference. What this means is that in Fuss, l is an alias for storage location used as a parameter to invoke the method. To be clear:

public void Fuss(ref List<int> l)

called by

List<int> list = new List<int> { 1, 2, 3 };
Fuss(list);

Now, in Fuss, l is an alias for list. In particular, if you assign a new instance of List<int> to l, the caller will see that new instance assigned to the variable list as well. In particular, if you say

public void Fuss(ref List<int> l) {
    l = new List<int> { 1 };
}

then the caller will now see a list with one element. But if you say

public void Fuss(List<int> l) {
    l = new List<int> { 1 };
}

and call by

List<int> list = new List<int> { 1, 2, 3 };
Fuss(list);

then the caller will still see list as having three elements.

Clear?

like image 45
jason Avatar answered Oct 11 '22 14:10

jason


It does not act like its passed by ref.

void ChangeMe(List<int> list) {
  list = new List<int>();
  list.Add(10);
}
void ChangeMeReally(ref List<int> list) {
  list = new List<int>();
  list.Add(10);
}

Try it. Do you notice the difference?

You can only change the contents of list (or any reference type) if you pass it without a ref (because as others have said, you are passing a reference to the object on the heap and thus change the same "memory").

However you cannot change "list", "list" is a variable that points to an object of type List. You can only change "list" if you pass it by reference (to make it point somewhere else). You get a copy of the reference, which if changed, can only be observed inside your method.

like image 79
chrisaut Avatar answered Oct 11 '22 13:10

chrisaut