Library tutorials & articles

Parameter Passing in C#

Value Parameters

There are four different kinds of parameters in C#: value parameters (the default), reference parameters (which use the ref modifier), output parameters (which use the out modifier), and parameter arrays (which use the params modifier). You can use any of them with both value and reference types. When you hear the words "reference" or "value" used (or use them yourself) you should be very clear in your own mind whether you mean that a parameter is a reference or value parameter, or whether you mean that the type involved is a reference or value type. If you can keep the two ideas separated, they're very simple.

By default, parameters are value parameters. This means that a new storage location is created for the variable in the function member declaration, and it starts off with the value that you specify in the function member invocation. If you change that value, that doesn't alter any variables involved in the invocation. For instance, if we have:

void Foo (StringBuilder x)
{
    x = null;
}
...
StringBuilder y = new StringBuilder();
y.Append ("hello");
Foo (y);
Console.WriteLine (y==null);

Output:

The value of y isn't changed just because x is set to null. Remember though that the value of a reference type variable is the reference - if two reference type variables refer to the same object, then changes to the data in that object will be seen via both variables. For example:

void Foo (StringBuilder x)
{
    x.Append (" world");
}
...
StringBuilder y = new StringBuilder();
y.Append ("hello");
Foo (y);
Console.WriteLine (y);

Output:

After calling Foo, the StringBuilder object that y refers to contains "hello world", as in Foo the data " world" was appended to that object via the reference held in x.

Now consider what happens when value types are passed by value. As I said before, the value of a value type variable is the data itself. Using the previous definition of the struct IntHolder, let's write some code similar to the above:

void Foo (IntHolder x)
{
    x.i=10;
}
...
IntHolder y = new IntHolder();
y.i=5;
Foo (y);
Console.WriteLine (y.i);

Output:

When Foo is called, x starts off as a struct with value i=5. Its i value is then changed to 10. Foo knows nothing about the variable y, and after the method completes, the value in y will be exactly the same as it was before (i.e. 5).

As we did earlier, check that you understand what would happen if IntHolder was declared as a class instead of a struct. You should understand why y.i would be 10 after calling Foo in that case.

Comments

  1. 21 Sep 2006 at 18:31

    So how do I pass a reference type by value - e.g. prevent changes/side effects to that instance?  Can this be done at all?

    Thanks

     

  2. 17 Jun 2005 at 08:15

    Nice layout. Easy to read and understand. Well done.

  3. 01 Jan 1999 at 00:00

    This thread is for discussions of Parameter Passing in C#.

Leave a comment

Sign in or Join us (it's free).

Jon Skeet C# MVP currently living in Reading and working for Google.
AddThis

Related podcasts

  • Object-Oriented Programming in Ruby

    In this episode, I talk with Scott Bellware about object-oriented programming in Ruby, and Ruby's object model. This is taken from a private conversation, and the audio quality suffers at times. Much thanks to Scott for allowing this to be released.This episode of the Alt.NET Podcast is bro...

Want to stay in touch with what's going on? Follow us on twitter!