When is using the C# ref keyword ever a good idea?
The more I see ref used in production code, the more misuse I encounter and the more pain it causes me. I have come to hate this keyword, because from a framework-building standpoint, it seems silly. When would it be a good idea to communicate to users of your code the notion of maybe changing an object reference/value out from beneath them?
By contrast, I love out keywords and I love even more when no keywords are used at all, in both cases because of the guarantees you're given when using them. Ref on the other hand makes no guarantees, except that you'll be forced to initialize the parameter before you pass it in, even though nothing may be changed about it.
I'm no sage developer though; I'm sure it's got practically applicable uses. I'd just like to know what they are.
The Framework Design Guidelines (a book by Krzysztof Cwalina and Brad Abrams) recommend to avoid both ref
and out
parameters.
AVOID using
out
orref
parameters.Using
out
orref
parameters requires experience with pointers, understanding how value types and reference types differ, and handling methods with multiple return values. Also, the difference betweenout
andref
parameters is not widely understood. Framework architects designing for a general audience should not expect users to master working without
orref
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
andref
altogether.
Most of the Interlocked
methods use ref
parameters for (I’m sure you agree) good reason.
I try to avoid it on public APIs, but it definitely has uses. Mutable value-types is an important one, especially on things like CF (where mutable structs are more common, due to platform requirements). However, perhaps the most common time I use it is when refactoring parts of a complex algorithm out into a few methods, where a state object is overkill and I need to pass multiple values around:
i.e.
var x = .....
var y = .....
// some local code...
var z = DoSomethingSpecific(ref x, ref y); // needs and updates x/y
// more local code...
etc. Where DoSomethingSpecific
is a private method, just moved out to keep method responsibility manageable.
Any time you want to change the value of a value type - this happens a lot in cases where you want to efficiently update a pair of related values (i.e. rather than returning a struct containing two ints, you pass (ref int x, ref int y))