Passing Arrays by Value and by Reference

In C#, a variable that "stores" an object, such as an array, does not actually store the object itself. Instead, such a variable stores a reference to the object (i.e., the location in the computer's memory where the object itself is stored). The distinction between reference-type variables and value-type variables raises some subtle issues that you must understand to create secure, stable programs.

As you know, when an application passes an argument to a method, the called method receives a copy of that argument's value. Changes to the local copy in the called method do not affect the original variable in the caller. If the argument is of a reference type, the method makes a copy of the reference, not a copy of the actual object that is referenced. The local copy of the reference also refers to the original object in memory, which means that changes to the object in the called method affect the original object in memory.

Performance Tip 8 1

Passing arrays and other objects by reference makes sense for performance reasons. If arrays were passed by value, a copy of each element would be passed. For large, frequently passed arrays, this would waste time and would consume considerable storage for the copies of the arraysboth of these problems cause poor performance.

In Section 7.14, you learned that C# allows variables to be passed by reference with keyword ref. You can also use keyword ref to pass a reference-type variable by reference, which allows the called method to modify the original variable in the caller and make that variable refer to a different object in memory. This is a subtle capability, which if misused, can lead to problems. For instance, when a reference-type object like an array is passed with ref, the called method actually gains control over the reference itself, allowing the called method to replace the original reference in the caller with a different object, or even with null. Such behavior can lead to unpredictable effects, which can be disastrous in mission-critical applications. The application in Fig. 8.14 demonstrates the subtle difference between passing a reference by value and passing a reference by reference with keyword ref.

Figure 8.14. Passing an array reference by value and by reference.

 1 // Fig. 8.14: ArrayReferenceTest.cs
 2 // Testing the effects of passing array references
 3 // by value and by reference.
 4 using System;
 5
 6 public class ArrayReferenceTest
 7 {
 8 public static void Main( string[] args )
 9 {
10 // create and initialize firstArray
11 int[] firstArray = { 1, 2, 3 };
12
13 // copy the reference in variable firstArray
14 int[] firstArrayCopy = firstArray;
15
16 Console.WriteLine(
17 "Test passing firstArray reference by value" );
18
19 Console.Write( "
Contents of firstArray " +
20 "before calling FirstDouble:
	" );
21
22 // print contents of firstArray
23 for ( int i = 0; i < firstArray.Length; i++ )
24 Console.Write( "{0} ", firstArray[ i ] );
25
26 // pass variable firstArray by value to FirstDouble
27 FirstDouble( firstArray ); 
28
29 Console.Write( "

Contents of firstArray after " +
30 "calling FirstDouble
	" );
31
32 // print contents of firstArray
33 for ( int i = 0; i < firstArray.Length; i++ )
34 Console.Write( "{0} ", firstArray[ i ] );
35
36 // test whether reference was changed by FirstDouble
37 if ( firstArray == firstArrayCopy )
38 Console.WriteLine(
39 "

The references refer to the same array" );
40 else
41 Console.WriteLine(
42 "

The references refer to different arrays" );
43
44 // create and initialize secondArray 45 int[] secondArray = { 1, 2, 3 }; 46 47 // copy the reference in variable secondArray 48 int[] secondArrayCopy = secondArray; 49 50 Console.WriteLine( " Test passing secondArray " + 51 "reference by reference" ); 52 53 Console.Write( " Contents of secondArray " + 54 "before calling SecondDouble: " ); 55 56 // print contents of secondArray before method call 57 for ( int i = 0; i < secondArray.Length; i++ ) 58 Console.Write( "{0} ", secondArray[ i ] ); 59 60 // pass variable secondArray by reference to SecondDouble 61 SecondDouble( ref secondArray ); 62 63 Console.Write( " Contents of secondArray " + 64 "after calling SecondDouble: " ); 65 66 // print contents of secondArray after method call 67 for ( int i = 0; i < secondArray.Length; i++ ) 68 Console.Write( "{0} ", secondArray[ i ] ); 69 70 // test whether reference was changed by SecondDouble 71 if ( secondArray == secondArrayCopy ) 72 Console.WriteLine( 73 " The references refer to the same array" ); 74 else 75 Console.WriteLine( 76 " The references refer to different arrays" ); 77 } // end method Main 78 79 // modify elements of array and attempt to modify reference 80 public static void FirstDouble( int[] array ) 81 { 82 // double each element's value 83 for ( int i = 0; i < array.Length; i++ ) 84 array[ i ] *= 2; 85 86 // create new object and assign its reference to array 87 array = new int[] { 11, 12, 13 }; 88 } // end method FirstDouble 89 90 // modify elements of array and change reference array 91 // to refer to a new array 92 public static void SecondDouble( ref int[] array ) 93 { 94 // double each element's value 95 for ( int i = 0; i < array.Length; i++ ) 96 array[ i ] *= 2; 97 98 // create new object and assign its reference to array 99 array = new int[] { 11, 12, 13 }; 100 } // end method SecondDouble 101 } // end class ArrayReferenceTest
 Test passing firstArray reference by value

 Contents of firstArray before calling FirstDouble:
 1 2 3

 Contents of firstArray after calling FirstDouble
 2 4 6

 The references refer to the same array

 Test passing secondArray reference by reference

 Contents of secondArray before calling SecondDouble:
 1 2 3

 Contents of secondArray after calling SecondDouble:
 11 12 13

 The references refer to different arrays

Lines 11 and 14 declare two integer array variables, firstArray and firstArrayCopy. Line 11 initializes firstArray with the values 1, 2 and 3. The assignment statement on line 14 copies the reference stored in firstArray to variable firstArrayCopy, causing these variables to reference the same array object in memory. We make the copy of the reference so that we can determine later whether reference firstArray gets overwritten. The for statement at lines 2324 prints the contents of firstArray before it is passed to method FirstDouble (line 27) so that we can verify that the array is passed by reference (i.e., the called method indeed changes the array's contents).

The for statement in method FirstDouble (lines 8384) multiplies the values of all the elements in the array by 2. Line 87 creates a new array containing the values 11, 12 and 13, and assigns the array's reference to parameter array in an attempt to overwrite reference firstArray in the callerthis, of course, does not happen, because the reference was passed by value. After method FirstDouble executes, the for statement at lines 3334 prints the contents of firstArray, demonstrating that the values of the elements have been changed by the method (and confirming that in C# arrays are always passed by reference). The if...else statement at lines 3742 uses the == operator to compare references firstArray (which we just attempted to overwrite) and firstArrayCopy. The expression in line 37 evaluates to true if the operands of operator == reference the same object. In this case, the object represented by firstArray is the array created in line 11not the array created in method FirstDouble (line 87)so the original reference stored in firstArray was not modified.

Lines 4576 perform similar tests, using array variables secondArray and secondArrayCopy, and method SecondDouble (lines 92100). Method SecondDouble performs the same operations as FirstDouble, but receives its array argument using keyword ref. In this case, the reference stored in secondArray after the method call is a reference to the array created in line 99 of SecondDouble, demonstrating that a variable passed with keyword ref can be modified by the called method so that the variable in the caller actually points to a different objectin this case, an array created in SecondDouble. The if...else statement in lines 7176 confirms that secondArray and secondArrayCopy no longer refer to the same array.

Software Engineering Observation 8 1

When a method receives a reference-type parameter by value, a copy of the object's reference is passed. This prevents a method from overwriting references passed to that method. In the vast majority of cases, protecting the caller's reference from modification is the desired behavior. If you encounter a situation where you truly want the called procedure to modify the caller's reference, pass the reference-type parameter using keyword refbut, again, such situations are rare.

Software Engineering Observation 8 2

In C#, objects (including arrays) are passed by reference by default. So, a called method receiving a reference to an object in a caller can change the caller's object.


Preface

Index

    Introduction to Computers, the Internet and Visual C#

    Introduction to the Visual C# 2005 Express Edition IDE

    Introduction to C# Applications

    Introduction to Classes and Objects

    Control Statements: Part 1

    Control Statements: Part 2

    Methods: A Deeper Look

    Arrays

    Classes and Objects: A Deeper Look

    Object-Oriented Programming: Inheritance

    Polymorphism, Interfaces & Operator Overloading

    Exception Handling

    Graphical User Interface Concepts: Part 1

    Graphical User Interface Concepts: Part 2

    Multithreading

    Strings, Characters and Regular Expressions

    Graphics and Multimedia

    Files and Streams

    Extensible Markup Language (XML)

    Database, SQL and ADO.NET

    ASP.NET 2.0, Web Forms and Web Controls

    Web Services

    Networking: Streams-Based Sockets and Datagrams

    Searching and Sorting

    Data Structures

    Generics

    Collections

    Appendix A. Operator Precedence Chart

    Appendix B. Number Systems

    Appendix C. Using the Visual Studio 2005 Debugger

    Appendix D. ASCII Character Set

    Appendix E. Unicode®

    Appendix F. Introduction to XHTML: Part 1

    Appendix G. Introduction to XHTML: Part 2

    Appendix H. HTML/XHTML Special Characters

    Appendix I. HTML/XHTML Colors

    Appendix J. ATM Case Study Code

    Appendix K. UML 2: Additional Diagram Types

    Appendix L. Simple Types

    Index



    Visual C# How to Program
    Visual C# 2005 How to Program (2nd Edition)
    ISBN: 0131525239
    EAN: 2147483647
    Year: 2004
    Pages: 600

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