Introduction
One might incorporate n number of methods to return or pass parameters while
method calling. Most of the time a developer try to escape using c# feature of
parameter passing by reference. Had he know the power of ref and out, a
developer will certainly make full use of this feature of parameter passing. My
effort in this article would be to make this understanding simpler and focus on
internal logic of ref and out.
Value Types vs. Reference Types Quick Overview)
As we know that in C# .NET there are two type of "types": reference types and
value types. Since they act in their own special way, so they must always be
used according to the real need and not by force.
Reference type variables have their value a reference to the appropriate data
rather than the data itself. Its ByRef in VB6,& in c++.
Value type directly contain the data and not the reference. And when assigned
the copy of that data is made to the assignment's elaborate, a new storage space
is created for the variable in the function member declaration, and it starts
off with the value that we specify in the member method calling. If we change
that value, it doesn't affect any variable involved in that call.
Why Pass by Reference ?
While writing code, we often come across situations where in we need to return
multiple values from a single function/method. But a method can only return a
single value. The question is how do we overcome such situation. Answer is
simple, use reference types, but how?
Let's throw some light on when to use the methodology . When you pass in a
variable to a method, the value of that variable gets copied to the method by
default. For values types, it means that the object itself gets copied on the
other end for reference types, it means that only the thing that points at the
object gets copied.
It is one way to save performance, else as larger as the reference type would be
as more performance it would cost. So we can also refer this as "Call by
Sharing". In a call by reference situation, if the variable of a reference type
is changed inside the method, the caller variable also gets affected. If we
change a the value of a value type, when passed to a method, it will never
affect the caller variable.
Our Target (Ref and Out)
Parameters are always passed by value to a method by default. If we want to pass
them by reference then we can use either out or ref keyword.
Reference parameters basically never pass the value of a variable used in the
method calling, instead they use the variable themselves. Rather than creating a
new storage for that variable in the method declaration, the very same storage
space is used, so the value of the variable in the member method and the value
of the reference parameter will always be the same. Reference parameters require
ref modifier as part of both the declaration and the calling.
Output parameters are very much like reference parameters. The variable
specified at the time of calling doesn't need to have been assigned a value
before it is passed to the called method. When the method is invoked completely
,We can read that variable as it is assigned by now.
Like reference parameters, output parameters don't create a new storage
location, but use the storage location of the variable specified on the
invocation. Output parameters need the out modifier as part of both the
declaration and the invocation - that means it's always clear when you're
passing something as an output parameter.
Consider the following scenario,
I have developed a simple console application to clarify the logic with the
following code in Program.cs class,
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
namespace
ref_and_out
{
class Program
{
static void
Main(string[] args)
{
string name1 = "Akhil";
string name2="Akhil";
Program program=new
Program();
Console.WriteLine("Name
Before Calling RefMethod : "+ name1);
program.RefMethod(ref
name1);
Console.WriteLine("Name
After Calling RefMethod : " + name1);
Console.WriteLine("Name
Before Calling OutMethod : " + name2);
program.OutMethod(out
name2);
Console.WriteLine("Name
After Calling OutMethod : " + name2);
Console.ReadLine();
}
private void
RefMethod(ref string
nameRef)
{
nameRef =
"Akhil Mittal";
}
private void
OutMethod(out string
nameOut)
{
Console.WriteLine(nameOut);
}
}
}
As we can see in the above easy to understand code, I have created two methods
RefMethod and OutMethod to handle passed parameter into their invocation. Just
to check what were the values of my variables before and after assignment ,When
I compiled the code I got the following compile time error,
Certainly the error helped me to discover some new facts about out and ref,
-
The parameter initially is considered not
assigned in case of out .
-
The variable specified at the time of calling
doesn't need to have been assigned a value before it is passed to the
function member. Its the responsibility of called method to assign it before
completing the execution so that we can read it.
I changed the code to ,
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
namespace
ref_and_out
{
class Program
{
static void
Main(string[] args)
{
string name1 = "Akhil";
string
name2;
Program program=new
Program();
Console.WriteLine("Name
Before Calling RefMethod : "+ name1);
program.RefMethod(ref
name1);
Console.WriteLine("Name
After Calling RefMethod : " + name1);
program.OutMethod(out
name2);
Console.WriteLine("Name
After Calling OutMethod : " + name2);
Console.ReadLine();
}
private void
RefMethod(ref string
nameRef)
{
nameRef =
"Akhil Mittal";
}
private void
OutMethod(out string
nameOut)
{
nameOut =
"Akhil Mittal in out method";
}
}
}
And as expected, it worked fine.
Then to check if same is the case with ref also, i again made some modifications
as,
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
namespace
ref_and_out
{
class Program
{
static void
Main(string[] args)
{
string
name1;
string name2;
Program program=new
Program();
Console.WriteLine("Name
Before Calling RefMethod : "+ name1);
program.RefMethod(ref
name1);
Console.WriteLine("Name
After Calling RefMethod : " + name1);
program.OutMethod(out
name2);
Console.WriteLine("Name
After Calling OutMethod : " + name2);
Console.ReadLine();
}
private void
RefMethod(ref string
nameRef)
{
nameRef =
"Akhil Mittal";
}
private void
OutMethod(out string
nameOut)
{
nameOut =
"Akhil Mittal in out method";
}
}
}
And yes, I got the compile time error,
That means unlike out type, In ref,
The Inside Story (Some points to remember)
-
Several inbuilt methods as "TryParse" (one of
my favorite) use out and not ref as the inside the internal implementation
the library mainly uses ref.
Therefore out is a special form of ref in which the referenced memory should
not be initialized before the call.
-
Both the method definition and the calling
method must explicitly use the ref / out keyword.
-
There is no "boxing" when a value type is
passed by reference.
-
Properties cannot be passed via out or ref, as
properties are actually methods.
-
Ref / out are not considered to be a part of
method signature at compile time, so methods cannot be overloaded, if the
only difference between them is that one of the methods takes a ref argument
and the other takes an out argument.
And so the final (running) code :
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
namespace
ref_and_out
{
class Program
{
static void
Main(string[] args)
{
string name1="Akhil";
string name2;
Program program=new
Program();
Console.WriteLine("Name
Before Calling RefMethod : "+ name1);
program.RefMethod(ref
name1);
Console.WriteLine("Name
After Calling RefMethod : " + name1);
program.OutMethod(out
name2);
Console.WriteLine("Name
After Calling OutMethod : " + name2);
Console.ReadLine();
}
private void
RefMethod(ref string
nameRef)
{
nameRef =
"Akhil Mittal";
}
private void
OutMethod(out string
nameOut)
{
nameOut =
"Akhil Mittal";
}
}
}
And the output,