Parameters by reference

By default, parameters are always pass by value. However, the CLR does allow you to pass parameters by reference. In C#, you can use the out or ref keywords for passing parameters by reference. When the compiler sees that you’ve used these keywords, it will emit code that passes the *address* of the parameter rather than its value.

Interestingly, these two keywords are identical from the CLR’s point of view. The story is completely different for the C# compiler since it uses them to see who is responsible for initializing the value of a variable. Using the *ref* keyword is the same as saying that the caller is responsible for initializing the value of the parameter. On the other hand, using the out leaves that responsibility for the method. Here’s some really simple (dumb) methods:

static void ChangeNameWithOut(out String name){
    name = DateTime.Now.ToString();
static void ChangeNameWithRef(ref String name){
    name = DateTime.Now.ToString();

Now, here’s how you can use both methods:

String name = "Luis";
String anotherName;
ChangeNameWithOut(out anotherName);
ChangeNameWithRef(ref name);

As you can see, you’re not initializing the anotherName method before passing it to the ChangeNameWithOut method. If you tried to pass anotherName to the ChangeNameWithRef method, you’d end up with a compilation error: Use of unassigned variable ‘anotherName’.

You’ve probably noticed that you’re forced to use the ref and out keywords on the call. For a long time, this puzzled me and I thought that the C# compiler should be able to infer that from the call. According to Jeffrey Richter, the designers of the language felt that the caller should make their intentions explicitly. I’m not sure I agree with that,but it’s just the way it is. And,as we’ll see next, this decision allows to overloads methods based on these keywords.

You can use the out and ref parameters for overloading methods, though you cannot add two overloads that differ only in out or ref only. Here’s some code that illustrate these principles:

static void ChangeName(String name){}
static void ChangeName(ref String name){} //ok
static void ChangeName(out String name){} //error

Adding the first overload won’t lead to a compilation error because you can overload methods by using the ref or out keywords. Adding the last method leads to a compilation error because you cannot add an overload that differs only by out and ref.

Besides overloading, there are some gotchas when you use reference parameters. Here’s a small example that might catch you off guard:

static void DoSomething(ref Object someParameter){}

var str = "Luis";
DoSomething(ref str);

You can’t compile the previous code. If you try, you’ll get an error saying that you cannot convert from ‘ref string’ to ‘ref object’. In other words, the parameter’s type must match the type of the value that is passed. In case you’re wondering, this is needed to ensure that type safety is preserved. The next snippet shows why this is a good thing:

static void DoSomething(ref Object someParameter){
    someParameter = new Student();

And I guess this sums it up nicely. There’s still some more about parameters, but we’ll leave it for future posts. Stay tuned for more.

~ by Luis Abreu on September 2, 2010.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: