When to Use Ref and When It Is Not Necessary in C#

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.

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 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 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.

What's the difference between the 'ref' and 'out' keywords?

ref tells the compiler that the object is initialized before entering the function, while out tells the compiler that the object will be initialized inside the function.

So while ref is two-ways, out is out-only.

why a class don't need to add ref?

In C# string datatype has the following properties:
• String is a reference type but behaves like a value type.
• Strings are immutable i.e., every time you change a string then a new string is created and the reference variable changes its reference to the newly created string.

A reference variable to an object type is always passed by reference (might seem tricky but you will get it if you continue reading :)).
But in case of string the reference variable passed by default is passed by value (unless you have explicitly use the ref keyword).
So in the following case:

String hello = "Hello";
MyFunction(hello);

A new reference variable will be created in MyFucntion that refers to the same location as hello string. But when you change the hello function inside the MyFucntion then actually contents of the newly created reference variable will be changed.

void MyFuntion(String hello)
{
//a new string will be created and the reference value of the
//local hello will be changed
hello = "Bye";
}

Let’s get into more details with the help of another example:
Consider the following code:

Inside main:

//let's create a string and pass it to a function as value and reference type
String str = "Hello World";
StringRefernecePassedByValue(str, ref str);
//the reference that was passed by value is the one that is the actual reference
//other one was a new refernece variable that has a copy of the reference
Console.WriteLine("Actual String: " + str);

The function called:

//The body of the function
static void StringRefernecePassedByValue(String valStr,ref String refStr)
{
//Both of the passed reference variable are pointing to the same location
Console.WriteLine("Are equal?: " + ReferenceEquals(valStr, refStr));

//let's change the strings
valStr = "Hello1";//a new string is created and now the valStr refer to it
refStr = "Hello2";//a new string is created and now the refStr refer to it

//let's confirm the output
Console.WriteLine("Passed by Value: " + valStr);
Console.WriteLine("Passed by Reference: " + refStr);

//now both are changed are are no more refering to the same location
Console.WriteLine("Are equal?: " + ReferenceEquals(valStr, refStr));
}

The output is:

Are equal?: True
Passed by Value: Hello1
Passed by Reference: Hello2
Are equal?: False
Actual String: Hello2

Now let’s do the above for a user defined type:

//a user defined datatype
class Student
{
public String name { get; set; }
public String cgpa { get; set; }
}

Inside main:

//let's observe in case of Custom type
Student student = new Student();
student.name = "Ali";
student.cgpa = "3.5";

ClassRefernecePassedByValue(student, ref student);
Console.WriteLine("Actual String: " + student.name);

The function to be called:

//the body of function
static void ClassRefernecePassedByValue(Student valStd, ref Student refStd)
{
//Both of the passed reference variable are pointing to the same location
Console.WriteLine("Are equal?: " + ReferenceEquals(valStd, refStd));

//let's change the objects
valStd.name = "Joseph";//changing the object refered by valStd
refStd.name = "Mick";//changing the object refered by refStd

Console.WriteLine("Passed by Value: " + valStd.name);
Console.WriteLine("Passed by Reference: " + refStd.name);

//now both are same
Console.WriteLine("Are equal?: " + ReferenceEquals(valStd, refStd));
}

The output:

Are equal?: True
Passed by Value: Mick
Passed by Reference: Mick
Are equal?: True
Actual String: Mick

Thus concluding that the reference to a string when passed to a function actually creates a new reference variable which contains a copied reference to another string reference variable but as string is an immutable type thus when the string pointed by the new reference variable changes then actual reference variable stays unchanged.
Sample Image

Also for further understanding you can get the complete code here

Why I need to use ref keyword in both declaration and Call?

This is because ref indicates that the parameter should be passed in by reference. It is something like pointer in C++

For example;

void CalFoo()
{
var i=10;
foo(ref i); //i=11
}
void foo(ref int i)
{
i++;
}

but

void CalFoo()
{
var i=10;
foo(i); //i=10
}
void foo(int i)
{
i++;
}

I think you can have both foo(ref int) and foo(int) in one single class. So if you don't specify the ref.. how does the compiler knows which one to call?

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;
}


Related Topics



Leave a reply



Submit