8.3. Returning Multiple ValuesMethods can return only a single value, but this isn't always convenient . Let's return to the Time class. It would be great to create a GetTime( ) method to return the hour , minutes, and seconds. You can't return all three of these as return values, but perhaps you can pass in three parameters, let the GetTime( ) method modify the parameters, and then examine the result in the calling methodin this case, Run( ) . Example 8-3 is a first attempt. Example 8-3. Retrieving multiple values, first attempt
The output will look something like this: 7/1/2008 12:22:19 Current time: 0:0:0 Notice that the "Current time" in the output is 0:0:0. Clearly, this first attempt did not work. The problem is with the parameters. You pass in three integer parameters to GetTime( ) , and you modify the parameters in GetTime( ) , but when the values are accessed back in Run( ) , they are unchanged. This is because integers are value types. 8.3.1. Passing Value Types by ReferenceAs discussed in Chapter 7, C# divides the world of types into value types and reference types. All intrinsic types (such as int and long ) are value types. Instances of classes (objects) are reference types. When you pass a value type (such as an int ) into a method, a copy is made. When you make changes to the parameter, you make changes to the copy. Back in the Run( ) method, the original integer variables theHour , theMinute , and theSecond are unaffected by the changes made in GetTime( ) . What you need is a way to pass in the integer parameters by reference so that changes made in the method are made to the original object in the calling method. When you pass an object by reference, the parameter refers to the same object. Thus when you make changes in GetTime( ) , the changes are also made to the original variables in Run( ) .
This requires two small modifications to the code in Example 8-3. First, change the parameters of the GetTime( ) method to indicate that the parameters are ref (reference) parameters: public void GetTime( ref int theHour, ref int theMinute, ref int theSecond ) { theHour = Hour; theMinute = Minute; theSecond = Second; } Second, modify the call to GetTime( ) to pass the arguments as references: t.GetTime(ref theHour, ref theMinute, ref theSecond);
These changes are shown in Example 8-4. Example 8-4. Passing by reference
This time, the output looks like this: 7/1/2008 12:25:41 Current time: 12:25:41 The results now show the correct time. By declaring these parameters to be ref parameters, you instruct the compiler to pass them by reference. Instead of a copy being made, the parameters in GetTime( ) are references to the corresponding variables ( theHour , theMinute , theSecond ) that were created in Run( ) . When you change these values in GetTime( ) , the change is reflected in Run( ) . Keep in mind that ref parameters are references to the actual original valueit is as if you said, "here, work on this one." Conversely, value parameters are copiesit is as if you said, "here, work on one just like this." 8.3.2. out Parameters and Definite AssignmentAs noted in Chapter 4, C# imposes definite assignment , which requires that all variables be assigned a value before they are used. In Example 8-4, you initialize theHour , theMinute , and theSecond before you pass them as parameters to GetTime( ) , yet the initialization merely sets their values to 0 before they are passed to the method: int theHour = 0; int theMinute = 0; int theSecond = 0; t.GetTime( ref theHour, ref theMinute, ref theSecond); It seems silly to initialize these values because you immediately pass them by reference into GetTime( ) where they'll be changed, but if you don't, the following compiler errors are reported : Use of unassigned local variable 'theHour' Use of unassigned local variable 'theMinute' Use of unassigned local variable 'theSecond' C# provides the out modifier for situations like this, in which initializing a parameter is only a formality . The out modifier removes the requirement that a reference parameter be initialized . The parameters to GetTime( ) , for example, provide no information to the method; they are simply a mechanism for getting information out of it. Thus, by marking all three as out parameters using the out keyword, you eliminate the need to initialize them outside the method. Within the called method, the out parameters must be assigned a value before the method returns. Here are the altered parameter declarations for GetTime( ) : public void GetTime( out int theHour, out int theMinute, out int theSecond ) { theHour = Hour; theMinute = Minute; theSecond = Second; } Here is the new invocation of the method in Main( ) : int theHour; int theMinute; int theSecond; t.GetTime( out theHour, out theMinute, out theSecond); The keyword out implies the same semantics as the keyword ref , except that it also allows you to use the variable without first initializing it in the calling method. |