Ken Kopczyk

Hurdles in .NET Development

Fun With the “ref” Keyword

Posted by Ken on February 3, 2009

By default, parameters are passed by value in C#.  Passing by reference requires the “ref” or “out” keywords to precede the parameter in both the method declaration and the call to the method.  Using “ref” or “out” is fairly straight forward…..or so I thought.

I recently came across two cases where parameters are valid if passing by value, but result in compilation errors after adding “ref”. Consider the following member and method:

// SuperDataTable inherits from DataTable
// Indexing a SuperDataTable yields a SuperDataRow 
// which inherits from DataRow.
private SuperDataTable mySuperDataTable = new SuperDataTable();

public void DoSomethingSuper(ref DataRow myDataRow)
{
	return;
}

Now examine the following three scenarios:

// #1 You receive a compiler error "A property or indexer 
// may not be passed as an out or ref parameter"
DoSomethingSuper(ref mySuperDataTable[0]);

// #2 You receive a compiler error "Cannot convert from 
// 'ref SuperDataRow' to 'ref DataRow'
SuperDataRow mySuperDataRow = mySuperDataTable[0];
DoSomethingSuper(ref mySuperDataRow);

// #3 Only does it work in the following manner, when you 
// explicitly "upcast" the row to the exact type in the 
// signature of the method
DataRow myDataRow = mySuperDataTable[0];
DoSomethingSuper(ref myDataRow);

Try it again, this time passing by value. No compiler errors! I probably am just lacking an intimate understanding of “ref”, but this came out of left field for me and I haven’t seen it documented online. Can anybody fill me in as to why scenarios #1 and #2 don’t work?

Bookmark and Share

4 Responses to “Fun With the “ref” Keyword”

  1. pizer said

    Are you sure you understand the different kinds of types and parameters? It seems you don’t get the fundamental difference between value types and reference types. Check out:

    C# parameters

    #1 Just accept this rule. A property is not an object that can be bound to a reference. It’s just syntactic sugar for hiding function calls.

    #2 It tjhis was allowed you would have a hole in the type system because DoSomethingSuper would be allowed to change mySuperDataRow and make it point to some other subclass object (derived from DataRow) that is NOT a SuperDataRow.

    What do you think “mySuperDataRow” is? It already is a reference to a SuperDataRow object.

    -P

    • Ken said

      Ahhh haaa!! I’ll hand it to you pizer, you’re right on all counts (and what better way to learn than with an open forum, right??). Your explanation on scenario #2 makes sense. Also, the link you sent breaks down the ideas of value and reference very clearly. Into Delicious it goes….Good article! Thanks for the help!

  2. Mark said

    This is one thing I never liked about Java (and since C# is similar to Java in so many ways…). I learned to code in C and when coding in C you know exactly when you’re using a variable or a pointer to that variable. EVERYTHING is passed by value. If you want to pass by reference you pass the value of the pointer (or reference).

    What makes the modern OO languages confusing is that you don’t need to indicate that you’re using a reference by placing a * before the variable declaration and dereference it before each use. It’s easy to forget what’s going on behind the scenes when the language hides this from the coder.

    Pizer’s link was indeed helpful. I like that it covered the ever ignored struct. I’ve always thought it was a poor choice of C# to define DateTime with capital letters since it’s a struct and not a class. It’s immutable just like a string.

  3. Ken said

    As I mentioned at the top, in C#, *everything* is passed by value unless the ref keyword is used. But parameter passing works differently depending on if you’re passing a value type or reference type.

    Value types are structs, enums, bool and numeric types. Reference types (pointers) are basically everything else.

    Passing Value Type by Value: A copy of the memory used to store the value type is created. The value type that was passed to the method will not be affected by anything that happens within the method. There are two independent copies of the data.

    Passing Value Type by Reference: A pointer to the Value Type’s memory is passed. Changing the value type within the method affects the value type that was passed to the method because they point to the same thing.

    Passing Reference Type by Value: A pointer to some memory is copied. There will be two pointers to the same memory location. Redirecting one of the pointers to null, for example, will not effect the other.

    Passing Reference Type by Reference: The same pointer is passed to the method. Whatever happens inside the method affects the object on the outside of the method.

    That’s the jist of it. I think this article does a better job explaining than I can, but the important thing to take away is that there are four possible ways to pass parameters. Knowing the subtleties of each is key.

Leave a Reply to Mark Cancel reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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: