Passing Arguments: Pass-by-Value vs. Pass-by-Reference

Passing Arguments Pass by Value vs Pass by Reference

Two ways to pass arguments to functions in many programming languages are pass-by-value and pass-by-reference. When an argument is passed by value (the default in C#), a copy of the argument's value is made and passed to the called function. Changes to the copy do not affect the original variable's value in the caller. This prevents the accidental side effects that so greatly hinder the development of correct and reliable software systems. Each argument that has been passed in the programs in this chapter so far has been passed by value. When an argument is passed by reference, the caller gives the method the ability to access and modify the caller's original variable.

Performance Tip 7 1

Pass-by-reference is good for performance reasons, because it can eliminate the pass-by-value overhead of copying large amounts of data.

Software Engineering Observation 7 5

Pass-by-reference can weaken security, because the called function can corrupt the caller's data.

To pass an object by reference into a method, simply provide as an argument in the method call the variable that refers to the object. Then, in the method body, reference the object using the parameter name. The parameter refers to the original object in memory, so the called method can access the original object directly.

Previously, we discussed the difference between value types and reference types. One of the major differences between them is that value-type variables store values, so specifying a value-type variable in a method call passes a copy of that variable's value to the method. Reference-type variables store references to objects, so specifying a reference-type variable as an argument passes the method a copy of the actual reference that refers to the object. Even though the reference itself is passed by value, the method can still use the reference it receives to modify the original object in memory. Similarly, when returning information from a method via a return statement, the method returns a copy of the value stored in a value-type variable or a copy of the reference stored in a reference-type variable. When a reference is returned, the calling method can use that reference to interact with the referenced object. So, in effect, objects are always passed by reference.

What if you would like to pass a variable by reference so the called method can modify the variable's value? To do this, C# provides keywords ref and out. Applying the ref keyword to a parameter declaration allows you to pass a variable to a method by referencethe called method will be able to modify the original variable in the caller. The ref keyword is used for variables that already have been initialized in the calling method. Normally, when a method call contains an uninitialized variable as an argument, the compiler generates an error. Preceding a parameter with keyword out creates an output parameter. This indicates to the compiler that the argument will be passed into the called method by reference and that the called method will assign a value to the original variable in the caller. If the method does not assign a value to the output parameter in every possible path of execution, the compiler generates an error. This also prevents the compiler from generating an error message for an uninitialized variable that is passed as an argument to a method. A method can return only one value to its caller via a return statement, but can return many values by specifying multiple output parameters.

You can also pass a reference-type variable by reference, which allows you to modify the passed reference-type variable so that it references a new object. Passing a reference by reference is a tricky but powerful technique that we discuss in Section 8.8.

The application in Figs. 7.18 and 7.19 uses the ref and out keywords to manipulate integer values. Class ReferenceAndOutputParameters (Fig. 7.18) contains three methods that calculate the square of an integer. Method SquareRef (lines 3740) multiplies its parameter x by itself and assigns the new value to x. SquareRef's parameter x is declared as ref int, which indicates that the argument passed to this method must be an integer that is passed by reference. Because the argument is passed by reference, the assignment at line 39 modifies the original argument's value in the caller.

Figure 7.18. Reference, output and value parameters.

 1 // Fig. 7.18: ReferenceAndOutputParameters.cs
 2 // Reference, output and value parameters.
 3 using System;
 4
 5 class ReferenceAndOutputParameters
 6 {
 7 // call methods with reference, output and value parameters
 8 public void DemonstrateReferenceAndOutputParameters()
 9 {
10 int y = 5; // initialize y to 5
11 int z; // declares z, but does not initialize it
12
13 // display original values of y and z
14 Console.WriteLine( "Original value of y: {0}", y );
15 Console.WriteLine( "Original value of z: uninitialized
" );
16
17 // pass y and z by reference
18 SquareRef( ref y ); // must use keyword ref
19 SquareOut( out z ); // must use keyword out
20
21 // display values of y and z after they are modified by
22 // methods SquareRef and SquareOut, respectively
23 Console.WriteLine( "Value of y after SquareRef: {0}", y );
24 Console.WriteLine( "Value of z after SquareOut: {0}
", z );
25
26 // pass y and z by value
27 Square( y );
28 Square( z );
29
30 // display values of y and z after they are passed to method Square
31 // to demonstrate arguments passed by value are not modified
32 Console.WriteLine( "Value of y after Square: {0}", y );
33 Console.WriteLine( "Value of z after Square: {0}", z );
34 } // end method DemonstrateReferenceAndOutputParameters
35
36 // uses reference parameter x to modify caller's variable
37 void SquareRef( ref int x )
38 {
39 x = x * x; // squares value of caller's variable 40 } // end method SquareRef 41 42 // uses output parameter x to assign a value 43 // to an uninitialized variable 44 void SquareOut( out int x ) 45 { 46 x = 6; // assigns a value to caller's variable 47 x = x * x; // squares value of caller's variable 48 } // end method SquareOut 49 50 // parameter x receives a copy of the value passed as an argument, 51 // so this method cannot modify the caller's variable 52 void Square( int x ) 53 { 54 x = x * x; 55 } // end method Square 56 } // end class ReferenceAndOutputParameters

Figure 7.19. Application to test class ReferenceAndOutputParameters.

 1 // Fig. 7.19: ReferenceAndOutputParamtersTest.cs
 2 // Application to test class ReferenceAndOutputParameters.
 3 class ReferenceAndOutputParamtersTest
 4 {
 5 static void Main( string[] args )
 6 {
 7 ReferenceAndOutputParameters test =
 8 new ReferenceAndOutputParameters();
 9 test.DemonstrateReferenceAndOutputParameters();
10 } // end Main
11 } // end class ReferenceAndOutputParamtersTest
 
Original value of y: 5
Original value of z: uninitialized

Value of y after SquareRef: 25
Value of z after SquareOut: 36

Value of y after Square: 25
Value of z after Square: 36

Method SquareOut (lines 4448) assigns its parameter the value 6 (line 46), then squares that value. SquareOut's parameter is declared as out int, which indicates that the argument passed to this method must be an integer that is passed by reference and that the argument does not need to be initialized in advance.

Method Square (lines 5255) multiplies its parameter x by itself and assigns the new value to x. When this method is called, a copy of the argument is passed to the parameter x. Thus, even though parameter x is modified in the method, the original value in the caller is not modified.

Method DemonstrateReferenceAndOutputParameters (lines 834) invokes methods SquareRef, SquareOut and Square. This method begins by initializing variable y to 5 and declaring, but not initializing, variable z. Lines 1819 call methods SquareRef and SquareOut. Notice that when you pass a variable to a method with a reference parameter, you must precede the argument with the same keyword (ref or out) that was used to declare the reference parameter. Lines 2324 display the values of y and z after the calls to SquareRef and SquareOut. Notice that y has been changed to 25 and z has been set to 36.

Lines 2728 call method Square with y and z as arguments. In this case, both variables are passed by valueonly copies of their values are passed to Square. As a result, the values of y and z remain 25 and 36, respectively. Lines 3233 output the values of y and z to show that they were not modified.

Common Programming Error 7 12

The ref and out arguments in a method call must match the parameters specified in the method declaration; otherwise, a compilation error occurs.

Software Engineering Observation 7 6

By default, C# does not allow you to choose whether to pass each argument by value or by reference. Value-types are passed by value. Objects are not passed to methods; rather, references to objects are passed to methods. The references themselves are passed by value. When a method receives a reference to an object, the method can manipulate the object directly, but the reference value cannot be changed to refer to a new object. In Section 8.8, you'll see that references also can be passed by reference.


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