Al C Al C - 2 months ago 8
C# Question

Alternatives to using ref keyword?

As a newbie I've read about the dangers of passing parameters with the

ref
keyword. I guess there's great potential to mess up code when a ref variable is modified in part of a program which then changes what happens elsewhere. Objects end up being very tightly coupled. (I recognize there may be places where
ref
is worthwhile
.) What I don't yet know, and am asking about, are the alternatives.

In one program, for example, I create a generic list at startup, which I manipulate in the program's methods. In one method:

//a user is asked a question
//if the response is yes, the list is modified one way and the method returns true
//if the response is no, the list is modified a different way and the method returns false.


So the method returns a Boolean and I pass the list in as a
ref
. I have several similar methods, each asking users unique questions and then modifying the list in some way.

It seems like a typical alternative might be to bundle the list and a Boolean field into its own class. Somehow this seems like creating an object for nothing more than convenience, just to hold two pieces of data, with no connection to any real world entity.

So, how would you (pseudo)code a method that returns both a generic list and a Boolean value?




EDIT: Here's some actual code

private static bool AskExptQuestion(ref List<StatTest> testList)
{
Console.Write(Constants.ExptQText); //experimental groups?
string response = Console.ReadLine();

//if response==y, it's experimental
if (response == "y")
{
//so select all experimental
var q1List =
from test in testList
where test.isExperimental == true
select test;

//to copy resulting IEnumerable<List> (q1list) to generic List, must copy/cast IEnumerable to a List<t>
testList = q1List.ToList();
return true;
}
//and if response==n, it's not experimental
else
{
//so select all non-experimental
var q1List =
from test in testList
where test.isExperimental == false
select test;

testList = q1List.ToList();
return false;
}

}

Answer

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.

Comments