views:

218

answers:

9

IS there a good use for inout (ref in C#, byref (like out parameters) in vb.net) parameters in .NET?
I feel that the confusion caused by a parameter used both as input and as a return value is worse that the increase in the number of parameters for out parameters, or returning an array or returning an custom class.

A: 

When you are likely to make a series of calls that modify the same variable.

It doesn't happen much in pointer-based languages like C# though, because you can just pass an object as an 'in' parameter and the called function can call its methods to modify it as necessary.

finnw
A: 

In some rare cases it can be useful, mostly for performance reasons.

In most cases it can, and in my opinion it should, be avoided by returning an array or a custom class as you mention.

Guffa
A: 

Ref and out parameter passing modes are used to allow a method to alter variables passed in by the method caller.

Each parameter passing mode (ref and out) is designed to suite different programming needs.

The caller of a method which takes an out parameter is not required to assign to the variable passed as the out parameter prior to the call; however, the method is required to assign to the out parameter before returning.

One way to think of out parameters is that they are like additional return values of a method. They are convenient when a method should return more than one value.

Do not confuse the concept of passing by reference with the concept of reference types.

The two concepts are not related; a method parameter can be modified by ref regardless of whether it is a value type or a reference type, there is no boxing of a value type when it is passed by reference.

CMS
+5  A: 

The most common use (which still isn't that common, IMO) I've come across is a sort of "modify an existing object, or create one if necessary". For example:

public void AppendToBuilder(ref StringBuilder builder)
{
    if (builder == null)
    {
        builder = new StringBuilder();
    }
    builder.Append(/* whatever */);
}

StringBuilder probably isn't a great example, but it means you can sometimes avoid creating an object when you don't need to:

public static string DoSomething(IEnumerable<Foo> foos)
{
    // For an empty collection or where there aren't any
    // frobulating foos, we don't need to create a builder
    StringBuilder builder = null;
    foreach (Foo foo in foos)
    {
        if (foo.Frobulates)
        {
            foo.AppendToBuilder(ref builder);
        }
    }
    return builder == null ? null : builder.ToString();
}
Jon Skeet
A: 

I've used it with an value-type parameter in a graphics routine that printed text to a GDI window in a vertical layout. The inout parameter kept track of the current Y position:

WriteString("hello", ref y);

rather than

y += WriteString("hello", y);
Jeff Kotula
A: 

Out is good for simple cases which require multiple return values. This way you don't get confused by "is it a parameter/is it a return value" that ref might cause.

public void GetStockQuote(
  string stock, 
  out double lastTrade, 
  out DateTime tradeTime, 
  out double change, 
  out double open)
{
  //perform stock magic here
}
Will
Those are all "out" though - the question is about "ref". (I would say that in your example, that's crying out for an encapsulated type.)
Jon Skeet
Reread the question... Thought he meant in/out, or both. And, yes, the example isn't exactly the best way to go about it.
Will
+5  A: 

I've used it mostly for adapting to legacy code.= (com interop).

I also tend to use it in code that needs to be performant and indicate success:

bool PerformSomeReadOperation(SomeInput obj, ref int defaultedOutput) { }

where the return value is a notion of success or failure or perhaps an error code and defaultedOutput is a value that comes in with a default value.

Did you know that there is no real difference between out and ref (at least as far as the CLR is concerned)?

plinth
A: 

I use it when I want to modify a value and think a wrapper class is overkill.

For example

if (line[index].StartsWith("X12"))
    ParseX12(lines, ref index, builder); //eats 2 or 4 lines

else if (line[index].StartsWith("A27"))
    ParseA27(lines, ref index, builder); //eats 1 line

else if (line[index].StartsWith("B16"))
    ParseB16(lines, ref index, builder); //eats 1 to 3 lines

else 
    index++; //this line couldn't be parsed, skip to the next one

In this example the Parse functions may consume more than one line. Thus they are responsible for correctly updating the index variable.

Jonathan Allen
A: 

You've really answered you own question.

If it makes sense to pass data both in and out through a parameter - ie. if the method needs to know the present value and also is expected to update it (or, in the case of a reference type, replace it), then ref is right. It doesn't happen often, but when it does, you know what to use ;-)

Tor Haugen