Using ref and out Parameters


As just explained, value types, such as int or char, are passed by value to a method. This means that changes to the parameter that receives a value type will not affect the actual argument used in the call. You can, however, alter this behavior. Through the use of the ref and out keywords, it is possible to pass any of the value types by reference. Doing so allows a method to change the argument used in the call.

Before going into the mechanics of using ref and out, it is useful to understand why you might want to pass a value type by reference. In general, there are two reasons: to allow a method to alter the contents of its arguments or to allow a method to return more than one value. Let’s look at each reason in detail.

Often you will want a method to be able to operate on the actual arguments that are passed to it. The quintessential example of this is a swap( ) method that exchanges the values of its two arguments. Since value types are passed by value, it is not possible to write a method that swaps the value of two ints, for example, using C#’s default call-by-value parameter passing mechanism. The ref modifier solves this problem.

As you know, a return statement enables a method to return a value to its caller. However, a method can return only one value each time it is called. What if you need to return two or more pieces of information? For example, what if you want to create a method that decomposes a floating-point number into its integer and fractional parts? To do this requires that two pieces of information be returned: the integer portion and the fractional component. This method cannot be written using only a single return value. The out modifier solves this problem.

Using ref

The ref parameter modifier causes C# to create a call-by-reference, rather than a call-by-value. The ref modifier is used when the method is declared and when it is called. Let’s begin with a simple example. The following program creates a method called sqr( ) that returns in-place the square of its integer argument. Notice the use and placement of ref.

 // Use ref to pass a value type by reference. using System; class RefTest {   /* This method changes its argument.      Notice the use of ref. */   public void sqr(ref int i) {     i = i * i;   } } class RefDemo {   public static void Main() {     RefTest ob = new RefTest();     int a = 10;     Console.WriteLine("a before call: " + a);     ob.sqr(ref a); // notice the use of ref     Console.WriteLine("a after call: " + a);   } }

Notice that ref precedes the entire parameter declaration in the method and that it precedes the name of the argument when the method is called. The output from this program, shown here, confirms that the value of the argument, a, was indeed modified by sqr( ):

 a before call: 10 a after call: 100

Using ref, it is now possible to write a method that exchanges the values of its two value-type arguments. For example, here is a program that contains a method called swap( ) that exchanges the values of the two integer arguments with which it is called:

 // Swap two values. using System; class Swap {   // This method now changes its arguments.   public void swap(ref int a, ref int b) {     int t;     t = a;     a = b;     b = t;   } } class SwapDemo {   public static void Main() {     Swap ob = new Swap();     int x = 10, y = 20;     Console.WriteLine("x and y before call: " + x + " " + y);     ob.swap(ref x, ref y);     Console.WriteLine("x and y after call: " + x + " " + y);   } }

The output from this program is shown here:

 x and y before call: 10 20 x and y after call: 20 10

Here is one important point to understand about ref: An argument passed by ref must be assigned a value prior to the call. The reason is that the method that receives such an argument assumes that the parameter refers to a valid value. Thus, using ref, you cannot use a method to give an argument an initial value.

Using out

Sometimes you will want to use a reference parameter to receive a value from a method, but not pass in a value. For example, you might have a method that performs some function, such as opening a network socket, that returns a success/fail code in a reference parameter. In this case, there is no information to pass into the method, but there is information to pass back out. The problem with this scenario is that a ref parameter must be initialized to a value prior to the call. Thus, to use a ref parameter would require giving the argument a dummy value just to satisfy this constraint. Fortunately, C# provides a better alternative: the out parameter.

An out parameter is similar to a ref parameter with this one exception: It can only be used to pass a value out of a method. It is not necessary (or useful) to give the variable used as an out parameter an initial value prior to calling the method. The method will give the variable a value. Furthermore, inside the method, an out parameter is considered unassigned; that is, it is assumed to have no initial value. This implies that the method must assign the parameter a value prior to the method’s termination. Thus, after the call to the method, an out parameter will contain a value.

Here is an example that uses an out parameter. In the class Decompose, the parts( ) method decomposes a floating-point number into its integer and fractional parts. Notice how each component is returned to the caller.

 // Use out. using System; class Decompose {   /* Decompose a floating-point value into its       integer and fractional parts. */   public int parts(double n, out double frac) {     int whole;     whole = (int) n;     frac = n - whole; // pass fractional part back through frac     return whole; // return integer portion   } } class UseOut {   public static void Main() {    Decompose ob = new Decompose();     int i;     double f;     i = ob.parts(10.125, out f);     Console.WriteLine("Integer portion is " + i);     Console.WriteLine("Fractional part is " + f);   } }

The output from the program is shown here:

 Integer portion is 10 Fractional part is 0.125

The parts( ) method returns two pieces of information. First, the integer portion of n is returned as parts( )’s return value. Second, the fractional portion of n is passed back to the caller through the out parameter frac. As this example shows, by using out, it is possible for one method to return two values.

Of course, you are not limited to only one out parameter. A method can return as many pieces of information as necessary through out parameters. Here is an example that uses two out parameters. The method hasComFactor( ) performs two functions. First, it determines if two integers have a common factor (other than 1). It returns true if they do and false otherwise. Second, if they do have a common factor, hasComFactor( ) returns the least and greatest common factors in out parameters.

 // Use two out parameters. using System; class Num {   /* Determine if x and y have a common divisor.      If so, return least and greatest common factors in      the out parameters. */   public bool hasComFactor(int x, int y,                            out int least, out int greatest) {     int i;     int max = x < y ? x : y;     bool first = true;     least = 1;     greatest = 1;     // find least and greatest common factors     for(i=2; i <= max/2 + 1; i++) {       if( ((y%i)==0) & ((x%i)==0) ) {         if(first) {           least = i;           first = false;         }         greatest = i;       }     }     if(least != 1) return true;     else return false;   } } class DemoOut {   public static void Main() {     Num ob = new Num();     int lcf, gcf;     if(ob.hasComFactor(231, 105, out lcf, out gcf)) {       Console.WriteLine("Lcf of 231 and 105 is " + lcf);       Console.WriteLine("Gcf of 231 and 105 is " + gcf);     }     else       Console.WriteLine("No common factor for 231 and 105.");     if(ob.hasComFactor(35, 51, out lcf, out gcf)) {       Console.WriteLine("Lcf of 35 and 51 " + lcf);       Console.WriteLine("Gcf of 35 and 51 is " + gcf);     }     else       Console.WriteLine("No common factor for 35 and 51.");   } }

In Main( ), notice that lcf and gcf are not assigned values prior to the call to hasComFactor( ). This would be an error if the parameters had been ref rather than out. The method returns either true or false, depending upon whether the two integers have a common factor. If they do, the least and greatest common factors are returned in the out parameters. The output from this program is shown here:

 Lcf of 231 and 105 is 3 Gcf of 231 and 105 is 21 No common factor for 35 and 51.

Using ref and out on References

The use of ref and out is not limited to the passing of value types. They can also be used when a reference is passed. When ref or out modifies a reference, it causes the reference, itself, to be passed by reference. This allows a method to change the object to which the reference refers. Consider the following program, which uses ref reference parameters to exchange the objects to which two references are referring:

 // Swap two references. using System; class RefSwap {   int a, b;   public RefSwap(int i, int j) {     a = i;     b = j;   }   public void show() {     Console.WriteLine("a: {0}, b: {1}", a, b);   }   // This method changes its arguments.   public void swap(ref RefSwap ob1, ref RefSwap ob2) {     RefSwap t;     t = ob1;     ob1 = ob2;     ob2 = t;   } } class RefSwapDemo {   public static void Main() {     RefSwap x = new RefSwap(1, 2);     RefSwap y = new RefSwap(3, 4);     Console.Write("x before call: ");     x.show();     Console.Write("y before call: ");     y.show();     Console.WriteLine();     // exchange the objects to which x and y refer     x.swap(ref x, ref y);     Console.Write("x after call: ");     x.show();     Console.Write("y after call: ");     y.show();   } }

The output from this program is shown here:

 x before call: a: 1, b: 2 y before call: a: 3, b: 4 x after call: a: 3, b: 4 y after call: a: 1, b: 2

In this example, the method swap( ) exchanges the objects to which the two arguments to swap( ) refer. Before calling swap( ), x refers to an object that contains the values 1 and 2, and y refers to an object that contains the values 3 and 4. After the call to swap( ), x refers to the object that contains the values 3 and 4, and y refers to the object that contains the values 1 and 2. If ref parameters had not been used, then the exchange inside swap( ) would have had no effect outside swap( ). You might want to prove this by removing ref from swap( ).




C# 2.0(c) The Complete Reference
C# 2.0: The Complete Reference (Complete Reference Series)
ISBN: 0072262095
EAN: 2147483647
Year: 2006
Pages: 300

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net