Pass References to Methods


Up to this point, the examples in this book have been using value types, such as int or double, as parameters to methods. However, it is both correct and common to use a reference type as a parameter. Doing so allows an object to be passed to a method. For example, consider the following program:

 // References can be passed to methods. using System; class MyClass {   int alpha, beta;   public MyClass(int i, int j) {     alpha = i;     beta = j;   }   /* Return true if ob contains the same values      as the invoking object. */   public bool sameAs(MyClass ob) {     if((ob.alpha == alpha) & (ob.beta == beta))        return true;     else return false;   }   // Make a copy of ob.   public void copy(MyClass ob) {     alpha = ob.alpha;     beta  = ob.beta;   }   public void show() {     Console.WriteLine("alpha: {0}, beta: {1}",                       alpha, beta);   } } class PassOb {   public static void Main() {     MyClass ob1 = new MyClass(4, 5);     MyClass ob2 = new MyClass(6, 7);     Console.Write("ob1: ");     ob1.show();     Console.Write("ob2: ");     ob2.show();     if(ob1.sameAs(ob2))       Console.WriteLine("ob1 and ob2 have the same values.");     else       Console.WriteLine("ob1 and ob2 have different values.");     Console.WriteLine();     // now, make ob1 a copy of ob2     ob1.copy(ob2);     Console.Write("ob1 after copy: ");     ob1.show();     if(ob1.sameAs(ob2))       Console.WriteLine("ob1 and ob2 have the same values.");     else       Console.WriteLine("ob1 and ob2 have different values.");   } }

This program generates the following output:

 ob1: alpha: 4, beta: 5 ob2: alpha: 6, beta: 7 ob1 and ob2 have different values. ob1 after copy: alpha: 6, beta: 7 ob1 and ob2 have the same values.

The sameAs( ) and copy( ) methods each take a reference of type MyClass as an argument. The sameAs( ) method compares the values of alpha and beta in the invoking object with the values of alpha and beta in the object passed to ob. The method returns true only if the two objects contain the same values for these instance variables. The copy( ) method assigns the values of alpha and beta in the object passed to ob to alpha and beta in the invoking object. As this example shows, syntactically, reference types are passed to methods in the same way as are value types.

How Arguments Are Passed

As the preceding example demonstrated, passing an object reference to a method is a straightforward task. However, there are some nuances that the example did not show. In certain cases, the effects of passing a reference type will be different than those experienced when passing a value type. To see why, let’s review the two ways in which an argument can be passed to a subroutine.

The first way is call-by-value. This method copies the value of an argument into the formal parameter of the subroutine. Therefore, changes made to the parameter of the subroutine have no effect on the argument used in the call. The second way an argument can be passed is call-by-reference. In this method, a reference to an argument (not the value of the argument) is passed to the parameter. Inside the subroutine, this reference is used to access the actual argument specified in the call. This means that changes made to the parameter will affect the argument used to call the subroutine.

By default, C# uses call-by-value, which means that a copy of the argument is made and given to the receiving parameter. Thus, when you pass a value type, such as int or double, what occurs to the parameter that receives the argument has no effect outside the method. For example, consider the following program:

 // Value types are passed by value. using System; class Test {   /* This method causes no change to the arguments      used in the call. */   public void noChange(int i, int j) {     i = i + j;     j = -j;   } } class CallByValue {   public static void Main() {     Test ob = new Test();     int a = 15, b = 20;     Console.WriteLine("a and b before call: " +                        a + " " + b);     ob.noChange(a, b);     Console.WriteLine("a and b after call: " +                        a + " " + b);   } }

The output from this program is shown here:

 a and b before call: 15 20 a and b after call: 15 20

As you can see, the operations that occur inside noChange( ) have no effect on the values of a and b used in the call. Again, this is because copies of the value of a and b have been given to parameters i and j, but a and b are otherwise completely independent of i and j. Thus, assigning i a new value will not affect a.

When you pass a reference to a method, the situation is a bit more complicated. In this case, the reference, itself, is still passed by value. Thus, a copy of the reference is made and changes to the parameter will not affect the argument. (For example, making the parameter refer to a new object will not change the object to which the argument refers.) However—and this is a big however—changes made to the object being referred to by the parameter will affect the object referred to by the argument. Let’s see why.

Recall that when you create a variable of a class type, you are only creating a reference to an object. Thus, when you pass this reference to a method, the parameter that receives it will refer to the same object as that referred to by the argument. This means that objects are passed to methods by what is effectively call-by-reference. Therefore, changes to the object inside the method do affect the object used as an argument. For example, consider the following program:

 // Objects are passed by reference. using System; class Test {   public int a, b;   public Test(int i, int j) {     a = i;     b = j;   }   /* Pass an object. Now, ob.a and ob.b in object      used in the call will be changed. */   public void change(Test ob) {     ob.a = ob.a + ob.b;     ob.b = -ob.b;   } } class CallByRef {   public static void Main() {     Test ob = new Test(15, 20);     Console.WriteLine("ob.a and ob.b before call: " +                        ob.a + " " + ob.b);     ob.change(ob);     Console.WriteLine("ob.a and ob.b after call: " +                        ob.a + " " + ob.b);   } }

This program generates the following output:

 ob.a and ob.b before call: 15 20 ob.a and ob.b after call: 35 -20

As you can see, in this case, the actions inside change( ) have affected the object used as an argument.

To review: When a reference is passed to a method, the reference itself is passed by use of call-by-value. Thus, a copy of that reference is made. However, the copy of that reference will still refer to the same object as its corresponding argument. This means that objects are implicitly passed using call-by-reference.




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