When Is Using the C# Ref Keyword Ever a Good Idea

When is using the C# ref keyword ever a good idea?

The Framework Design Guidelines (a book by Krzysztof Cwalina and Brad Abrams) recommend to avoid both ref and out parameters.

AVOID using out or ref parameters.

Using out or ref parameters requires experience with pointers, understanding how value types and reference types differ, and handling methods with multiple return values. Also, the difference between out and ref parameters is not widely understood. Framework architects designing for a general audience should not expect users to master working with out or ref parameters.

The Framework Design Guidelines cite the canonical Swap method as a valid exception:

void Swap<T>(ref T obj1, ref T obj2)
{
T temp = obj1;
obj1 = obj2;
obj2 = temp;
}

but at the same time a comment remarks

Swap always comes up in these discussions, but I have not written code that actually needed a swap method since college. Unless you've got a very good reason, avoid out and ref altogether.

Why use the 'ref' keyword when passing an object?

Pass a ref if you want to change what the object is:

TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(ref t);

void DoSomething(ref TestRef t)
{
t = new TestRef();
t.Something = "Not just a changed t, but a completely different TestRef object";
}

After calling DoSomething, t does not refer to the original new TestRef, but refers to a completely different object.

This may be useful too if you want to change the value of an immutable object, e.g. a string. You cannot change the value of a string once it has been created. But by using a ref, you could create a function that changes the string for another one that has a different value.

It is not a good idea to use ref unless it is needed. Using ref gives the method freedom to change the argument for something else, callers of the method will need to be coded to ensure they handle this possibility.

Also, when the parameter type is an object, then object variables always act as references to the object. This means that when the ref keyword is used you've got a reference to a reference. This allows you to do things as described in the example given above. But, when the parameter type is a primitive value (e.g. int), then if this parameter is assigned to within the method, the value of the argument that was passed in will be changed after the method returns:

int x = 1;
Change(ref x);
Debug.Assert(x == 5);
WillNotChange(x);
Debug.Assert(x == 5); // Note: x doesn't become 10

void Change(ref int x)
{
x = 5;
}

void WillNotChange(int x)
{
x = 10;
}

Why is the `ref` keyword not mandatory here?

ref is ment to be used when you change the reference, not the referenced instance. So you can modify the referenced instance without using ref, however when you want to reference another object, you have to use ref

Having said this Fill will just modify what was passed to it, it won´t create a new DataTable.

On the other hand when you want to return another instance, you have to use ref:

void DoSomething(ref dt)
{
dt = new DataTable();
// do something with the new table
}

Now you have two tables, one that was passed to DoSomething and a second one that was created within that method and that doesn´t have anything in common with the former. However the calling code references that new instance now, the original reference is lost.

When to use ref and when it is not necessary in C#

Short answer: read my article on argument passing.

Long answer: when a reference type parameter is passed by value, only the reference is passed, not a copy of the object. This is like passing a pointer (by value) in C or C++. Changes to the value of the parameter itself won't be seen by the caller, but changes in the object which the reference points to will be seen.

When a parameter (of any kind) is passed by reference, that means that any changes to the parameter are seen by the caller - changes to the parameter are changes to the variable.

The article explains all of this in more detail, of course :)

Useful answer: you almost never need to use ref/out. It's basically a way of getting another return value, and should usually be avoided precisely because it means the method's probably trying to do too much. That's not always the case (TryParse etc are the canonical examples of reasonable use of out) but using ref/out should be a relative rarity.

Use of 'ref' keyword in C#

Using ref means that the reference is passed to the function.

The default behaviour is that the function receives a new reference to the same object. This means if you change the value of the reference (e.g. set it to a new object) then you are no longer pointing to the original, source object. When you pass using ref then changing the value of the reference changes the source reference - because they are the same thing.

Consider this:

public class Thing
{
public string Property {get;set;}
}

public static void Go(Thing thing)
{
thing = new Thing();
thing.Property = "Changed";
}

public static void Go(ref Thing thing)
{
thing = new Thing();
thing.Property = "Changed";
}

Then if you run

var g = new Thing();

// this will not alter g
Go(g);

// this *will* alter g
Go(ref g);

In C#, where do you use ref in front of a parameter?

In my opinion, ref largely compensated for the difficulty of declaring new utility types and the difficulty of "tacking information on" to existing information, which are things that C# has taken huge steps toward addressing since its genesis through LINQ, generics, and anonymous types.

So no, I don't think there are a lot of clear use cases for it anymore. I think it's largely a relic of how the language was originally designed.

I do think that it still makes sense (like mentioned above) in the case where you need to return some kind of error code from a function as well as a return value, but nothing else (so a bigger type isn't really justified.) If I were doing this all over the place in a project, I would probably define some generic wrapper type for thing-plus-error-code, but in any given instance ref and out are OK.

What is the advantage of using the ref keyword with a reference type parameter?

What do I gain, as the developer, by passing a reference type argument to a method using the ref keyword if you are not changing what the reference points to?

None whatsoever - that's the only purpose of passing a reference type by reference is if you are going to change what the reference refers to.

To be fair - it gives you the ability to change that behavior in the future, which would be sadistic and cruel...

Alternatives to using ref keyword?

Returning a list (or almost anything else, for that matter) along with its characteristic, such as a Boolean value, is a "poster child" of the ref/out feature. This pattern is used in several places in the standard .NET library:

  • Dictionary.TryGetValue uses this pattern, returning true or false depending on presence of the key in the dictionary, and setting a out to the return object
  • Integer.TryParse (and other numeric types) use this pattern, returning true when the parse is successful, and setting the value in a out parameter

The difference between ref and out is that ref gives your method an option to keep the old object/value or to supply a new one, while the out forces you to supply a new one before the method returns.

There is no point to create a new class simply to bundle two unrelated types together.

In addition, it is important to understand that modifications to method parameters can happen even in situations when a parameter is not passed by ref or out. When you pass an object of reference (i.e. class) type that is mutable, any modifications to the object done inside the method are visible in the caller.

The only difference when passing by ref or out is that you are allowed to replace the object itself with a new one, while passing a reference type without ref is restricted to mutating the incoming object itself.

When to use in vs ref vs out

You should use out unless you need ref.

It makes a big difference when the data needs to be marshalled e.g. to another process, which can be costly. So you want to avoid marshalling the initial value when the method doesn't make use of it.

Beyond that, it also shows the reader of the declaration or the call whether the initial value is relevant (and potentially preserved), or thrown away.

As a minor difference, an out parameter needs not be initialized.

Example for out:

string a, b;
person.GetBothNames(out a, out b);

where GetBothNames is a method to retrieve two values atomically, the method won't change behavior whatever a and b are. If the call goes to a server in Hawaii, copying the initial values from here to Hawaii is a waste of bandwidth. A similar snippet using ref:

string a = String.Empty, b = String.Empty;
person.GetBothNames(ref a, ref b);

could confuse readers, because it looks like the initial values of a and b are relevant (though the method name would indicate they are not).

Example for ref:

string name = textbox.Text;
bool didModify = validator.SuggestValidName(ref name);

Here the initial value is relevant to the method.



Related Topics



Leave a reply



Submit