Question

Maybe an old question, but am not finding anything comprehensive on the internet.

If the default parameter passing method in C# is By value, then how does it affect the initial Reference Type variable?

I.e. in the below example, why will it print "Hello World" instead of just "Hello", if it was parameter passing by value?

void Foo (StringBuilder x)
{
    x.Append (" World");
}   

StringBuilder y = new StringBuilder();
y.Append ("Hello");
Foo (y);
Console.WriteLine (y);
Was it helpful?

Solution

Anything other than the primitive types (such as int, byte etc) are passed by reference by default. You are passing the same StringBuilder instance to the method.

OTHER TIPS

First, understand that in C# there are two fundamental types: Value Types and Reference Types.

Furthermore, each of those types can be passed to a method By Value or By Reference. (So, that means there are actually four ways to pass a parameter to a method.)

And regardless of how you pass a Reference Type (By Value or by Reference), you have the ability to change the value to which that reference points!

Now, with regard to your particular example, your parameter of question is of type StringBuilder which is a Reference Type. (StringBuilder is a Class and Classes are Reference Types.) And again, because you are passing a Reference Type to your method, you are able to change the value associated with that reference inside of that method.

Finally, note that you are passing your Reference Type parameter By Value. If instead you were to pass your Reference Type By Reference and then set it to null, you would actually destroy the value associated with the reference. (That would be the same as setting the parameter variable to null outside of the method.)

You can find a more more thorough and very readable explanation here: C# Concepts: Value vs Reference Types

That parameter is still a pass-by-value but parameter variable x has a reference of the StringBuilder object.

The reference variable y has the reference of StringBuilder object

StringBuilder y = new StringBuilder();

and reference of StringBuilder object is copied to parameter x of Foo.

Foo (y);

Because StringBuilder is a mutable class and will passed by reference. Instead of string builder you use string it will be Hello because string is immutable. Also for value types like int, enum, ... there isn't any change.

For simplicity, Value types are struct, enum, primitive types, ... and reference types are classes, but As I mentioned there are some classes like string which are immutable and in fact, they will be passed by value.

StringBuilder is a class, so it will be passed by reference.

read more: Value vs reference types

Compare the following. First with StringBuilder (reference type):

    public struct Tmd
    {
        public StringBuilder sb;
    }

    public void DoIt(Tmd a)
    {
        a.sb.Append(" World!");
    }

    public void Main()
    {
        Tmd a = new Tmd();
        a.sb = new StringBuilder();
        a.sb.Append("Hello");
        DoIt(a);
        Console.WriteLine(a.sb); // Hello World
    }

Here the struct is copied, as is the reference to the StringBuilder along with it, but the StringBuilder itself is not copied.

And now with a mutable struct (value type):

    public struct EvilMutable
    {
        public int i;
    }

    public struct Tmd
    {
        public EvilMutable em;
    }

    public void DoIt(Tmd a)
    {
        a.em.i += 1;
    }

    public void DoIt(EvilMutable em)
    {
        em.i += 1;
    }

    public void Main()
    {
        Tmd a = new Tmd();
        a.em.i += 5;
        Console.WriteLine(a.em.i); // 5
        DoIt(a);
        Console.WriteLine(a.em.i); // 5 (unchanged)
        DoIt(a.em);
        Console.WriteLine(a.em.i); // 5 (unchanged)
    }

In this case everything copied. However if we change this into a reference type:

    public class Tmd
    {
        public EvilMutable em;
    }

Then, we'll get this:

        Tmd a = new Tmd();
        a.em.i += 5;
        Console.WriteLine(a.em.i); // 5
        DoIt(a);
        Console.WriteLine(a.em.i); // 6
        DoIt(a.em);
        Console.WriteLine(a.em.i); // 6 (unchanged)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top