26

Taking my first steps in C# world from C/C++, so a bit hazy in details. Classes, as far as I understood, are passed by reference by default, but what about eg. List<string> like in:

void DoStuff(List<string> strs)
{
    //do stuff with the list of strings
}

and elsewhere

List<string> sl = new List<string>();
//next fill list in a loop etc. and then do stuff with it:
DoStuff(sl);

Is sl in this case passed by reference or is a copy made so that I'd need to redefine the worker function like

void DoStuff(ref List<string> strs)
to actually act on sl itself and not a copy?
stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
Scre
  • 454
  • 1
  • 10
  • 15
  • 8
    `class` is passed by reference. `struct` is passed by value. – Dialecticus May 06 '14 at 09:29
  • [this](http://yoda.arachsys.com/csharp/parameters.html) article should help you understand this area better. – Kurubaran May 06 '14 at 09:31
  • Seems "pass by reference" in C# and C++ are from different dictionaries. Anyhow, thank you all for the answers - hazy details now less hazy. – Scre May 06 '14 at 09:39
  • @Scre Some people confusingly use "pass by reference" in a different sense in C#, because of the terms "reference" and "reference type" (which indeed refer to a different meaning of "reference"). But the correct use of "pass by reference" in C#, `ref` parameters, is almost identical to the thing called pass by reference in C++ and CS in general. –  May 06 '14 at 09:46

7 Answers7

30

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

Adrian Ratnapala
  • 5,485
  • 2
  • 29
  • 39
11

The behaviour is always the same: Passing by copying. In case the parameter is an object, the reference to the object is copied, so in fact you are working on the same object/list/whatever.

Alexander Reifinger
  • 512
  • 1
  • 4
  • 18
8

In addition to other answers it is very important to understand the behavior of ref

Here is some sample code for demonstration purpose

static void Main(string[] args)
    {

        List<string> lstStr = new List<string>();

        lstStr.Add("First");
        lstStr.Add("Second");

        Alter(lstStr);

        //Alter(ref lstStr);

        Console.WriteLine("---From Main---");
        foreach (string s in lstStr)
        {
            Console.WriteLine(s);
        }

        Alter2(ref lstStr);

        Console.WriteLine("---From Main after passed by ref---");
        foreach (string s in lstStr)
        {
            Console.WriteLine(s);
        }

        Console.ReadKey();
    }

    static void Alter(List<string> lstStr2)
    {
        lstStr2.Add("Third");

        Console.WriteLine("----From Alter----");
        foreach (string s in lstStr2)
        {
            Console.WriteLine(s);
        }

        lstStr2 = new List<string>();
        lstStr2.Add("Something new");

        Console.WriteLine("----From Alter - after the local var is assigned somthing else----");

        foreach (string s in lstStr2)
        {
            Console.WriteLine(s);
        }

    }

    static void Alter2(ref List<string> lstStr2)
    {
        lstStr2 = new List<string>();
        lstStr2.Add("Something new from alter 2");

        Console.WriteLine("----From Alter2 - after the local var is assigned new list----");

        foreach (string s in lstStr2)
        {
            Console.WriteLine(s);
        }

    }


//----From Alter----
//First
//Second
//Third
//----From Alter - after the local var is assigned somthing else----
// Something new
// ---From Main---
// First
// Second
// Third
// ----From Alter2 - after the local var is assigned new list----
// Something new from alter 2
// ---From Main after passed by ref---
// Something new from alter 2
ZedBee
  • 2,320
  • 7
  • 39
  • 61
5

The underlying thing always is: value types are passed by value, and reference types are "passed by reference" (quoted because the value of the reference is actually passed by value, but most people ignore that for the sake of brevity).

The easiest way to reconcile the ref keyword against references is: reference types have their reference passed by value. This has the effect, in the standard case, of simply passing the reference to the list (and not the entire list) to the method.

The ref keyword, when used on a reference type, semantically passes a reference to the reference (I really struggle not to say "pointer to a pointer").

If your method were to re-assign the ref argument to a new object, the caller would also see this new assignment. Whereas without the ref keyword, the method would simply be re-assign their own local copy of the reference value and the caller would still have a reference to their original object.

The above explanation is shamelessly taken from Jon Skeet's article on the topic:

This difference is absolutely crucial to understanding parameter passing in C#, and is why I believe it is highly confusing to say that objects are passed by reference by default instead of the correct statement that object references are passed by value by default.

The ref keyword is only needed if you intend to re-assign the argument and have that visible to the caller. In most cases you will find that it isn't needed. Your DoStuff can be re-written to remove it and still pass a reference to the list by value successfully:

void DoSomething(List<string> strs) 
{ 
    strs.Add("Hello");
}
Adam Houldsworth
  • 63,413
  • 11
  • 150
  • 187
  • This was my first "hunch" about how it would work, but wasn't quite sure. – Scre May 06 '14 at 09:45
  • @scre I highly recommend reading that Jon Skeet article and also picking up the [C# in Depth](http://www.manning.com/skeet2/) book by him, he has a good skill for structuring an explanation of abstract or complex topics for easy consumption. – Adam Houldsworth May 06 '14 at 09:47
3

The ref keyword in your method is redundant if you want to modify the original list: List<T> is a reference type (class in C#) and so will be passed to the method by reference; therefore the method will manipulate the original list.

When passing a Value Type, it will create a copy of the value itself. When passing a Reference Type, it will create a copy of the reference.

Read more about Value and Reference Types in C#.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • 5
    The `ref` is not redundant. With it, `strs = ...;` affects the caller. Without it, it doesn't. –  May 06 '14 at 09:33
  • 2
    Also, sending a reference type object to a method without `ref` keyword results in creating a new copy of the reference. "Redundant" would mean it's the same. And it is not. – Tarec May 06 '14 at 09:35
2

The list is passed by reference. What that means is actually that the strs variable inside the method refers to the same list as the sl variable outside the method. If you would use ref, you can actually reassign the the sl variable inside the method.

strs = new List<string>()

would make sl point to the new list.

Since you're coming from C/C++: ref could be considered a 'safe pointer'. It is similar to using &strs

Dennis_E
  • 8,751
  • 23
  • 29
-2

Its by reference. Not necesary to include "ref".

Best regards.

fabian
  • 6
  • 2