So far, this chapter's examples have returned data via the method return. This section demonstrates the options of returning data via method parameters and via a variable number of parameters.

Beginner Topic: Matching Caller Variables with Parameter Names

In some of the previous listings, you matched the variable names in the caller with the parameter names in the target method. This matching is simply for readability; whether names match is entirely irrelevant to the behavior of the method call.

Value Parameters

By default, parameters are passed by value, which means that the variable's stack data is copied into the target parameter. For example, in Listing 4.11, each variable that Main() uses when calling Combine() will be copied into the parameters of the Combine() method. Output 4.5 shows the results of this listing.

Listing 4.11. Passing Variables by Value

 class Program {   static void Main()   {       // ...       string fullName;       string driveLetter = "C:";       string folderPath = "Data";       string fileName = "index.html";         fullName = Combine(driveLetter, folderPath, fileName);         Console.WriteLine(fullName);       // ...   }     static string Combine(       string driveLetter, string folderPath, string fileName)   {       string path;       path = string.Format("{1}{0}{2}{0}{3}",           System.IO.Path.DirectorySeparatorChar,           driveLetter, folderPath, fileName);       return path;   } } 

Output 4.5.


Even if the Combine() method assigns null to driveLetter, folderPath, and fileName before returning, the corresponding variables within Main() will maintain their original values because the variables are copied when calling a method. When the call stack unwinds at the end of a call, the copy is thrown away.

Advanced Topic: Reference Types Versus Value Types

For the purposes of this section, it is inconsequential whether the parameter passed is a value type or a reference type. The issue is whether the target method can assign the caller's original variable a new value. Since a copy is made, the caller's copy cannot be reassigned.

In more detail, a reference type variable contains an address of the memory location where the data is stored. If a reference type variable is passed by value, the address is copied from the caller to the method parameter. As a result, the target method cannot update the caller variable's address value. Alternatively, if the method parameter is a value type, the value itself is copied into the parameter, and changing the parameter will not affect the original caller's variable.

Reference Parameters (ref)

Consider Listing 4.12, which calls a function to swap two values, and Output 4.6, which shows the results.

Listing 4.12. Passing Variables by Reference

 class Program {   static void Main()   {       // ...       string first = "first";       string second = "second";       Swap(ref first, ref second);                                      System.Console.WriteLine(           @"first = " "{0}"", second = ""{1}""",           first, second);       // ...   }      static void Swap(ref string first, ref string second)              {       string temp = first;       first = second;       second = temp;   } } 

Output 4.6.

 first = "second", second = "first" 

The values assigned to first and second are successfully switched, even though there is no return from the Swap() method. To do this, the variables are passed by reference. The obvious difference between the call to Swap() and Listing 4.11's call to Combine() is the use of the keyword ref in front of the parameter's data type. This keyword changes the call type to be by reference, so the called method can update the original caller's variable with a new value.

When the called method specifies a parameter as ref, the caller is required to place ref in front of the variables passed. In so doing, the caller explicitly recognizes that the target method could reassign any ref parameters it receives. Furthermore, it is necessary to initialize variables passed as ref because target methods could read data from ref parameters without first assigning them. In Listing 4.12, for example, temp is assigned the value of first, assuming that the variable passed in first was initialized by the caller.

Output Parameters (out)

In addition to passing parameters into a method only (by value) and passing them in and back out (by reference), it is possible to pass data out only. To achieve this, code needs to decorate parameter types with the keyword out, as shown in the GetPhoneButton() method in Listing 4.13 that returns the phone button corresponding to a character.

Listing 4.13. Passing Variables Out Only

 class ConvertToPhoneNumber {   static int Main(string[] args)   {       char button;       if(args.Length == 0)       {           Console.WriteLine(               "ConvertToPhoneNumber.exe <phrase>");           Console.WriteLine(               "'_' indicates no standard phone button");           return 1;       }       foreach(string word in args)       {           foreach(char character in word)           {               if(GetPhoneButton(character, out button))                         {                   Console.Write(button);               }               else               {                   Console.Write('_');               }          }      }      Console.WriteLine();      return 0;  }    static bool GetPhoneButton(char character, out char button)          {     bool success = true;     switch( char.ToLower(character)     {         case '1':             button = '1';             break;         case '2': case 'a': case 'b': case 'c':             button = '2';             break;         case '3': case 'd': case 'e': case 'f':             button = '3';             break;         case '4': case 'g': case 'h': case 'i':             button = '4';             break;         case '5': case 'j': case 'k': case 'l':              button = '5';              break;         case '6': case 'm': case 'n': case 'o':              button = '6';              break;         case '7': case 'p': case 'q': case 'r': case 's':              button = '7';              break;          case '8': case 't': case 'u': case 'v':              button = '8';              break;          case '9': case 'w': case 'x': case 'y': case 'z':              button = '9';              break;          case '*':              button = '*';              break;          case '0':              button = '0';              break;          case '#':              button = '#';              break;          case ' ':              button = ' ';              break;          case '-':              button = '-';              break;          default:                // Set the button to indicate an invalid value              button = '_';              success = false;              break;       }       return success;    } } 

Output 4.7 shows the results of Listing 4.13.

Output 4.7.

 >ConvertToPhoneNumber.exe CSharpIsGood 274277474663 

In this example, the GetPhoneButton() method returns true if it can successfully determine the character's corresponding phone button. The function also returns the corresponding button by using the button parameter which is decorated with out.

Whenever a parameter is marked with out, the compiler will check that the parameter is set for all code paths within the method. If, for example, the code does not assign button a value, the compiler will issue an error indicating the code didn't initialize button. Listing 4.13 assigns button to _ because even though it cannot determine the correct phone button, it is still necessary to assign a value.

Parameter Arrays (params)

In all the examples so far, the number of parameters is fixed by the target method declaration. However, sometimes the number of parameters may vary. Consider the Combine() method from Listing 4.11. In that method, you passed the drive letter, folder path, and filename. What if the number of folders in the path was more than one and the caller wanted the method to join additional folders to form the full path? Perhaps the best option would be to pass an array of strings for the folders. However, this would make the calling code a little more complex, because it would be necessary to construct an array to pass as a parameter.

For a simpler approach, C# provides a keyword that enables the number of parameters to vary in the calling code instead of being set by the target method. Before the method declaration is discussed, observe the calling code declared within Main(), as shown in Listing 4.14.

Listing 4.14. Passing a Variable Parameter List

 using System.IO; class PathEx {   static void Main()   {       string fullName;       // ...       // Call Combine() with four parameters                                        fullName = Combine(                                                                         Directory.GetCurrentDirectory(),                                                           "bin", "config", "index.html");                                                      Console.WriteLine(fullName);         // ...        // Call Combine() with only three parameters                                     fullName = Combine(                                                                         Environment.SystemDirectory,                                                           "Temp", "index.html");                                                      Console.WriteLine(fullName);         // ...        // Call Combine() with an array                                                       fullName = Combine(                                                                        new string[] {                                                                      "C:\", "Data",                                                         "HomeDir", "index.html"} );                                                          Console.WriteLine(fullName);       // ...   }      static string Combine(params string[] paths)                     {         string result = string.Empty;         foreach (string path in paths)         {             result = System.IO.Path.Combine(result, path);         }         return result;     } } 

Output 4.8 shows the results of Listing 4.14.

Output 4.8.

 C:\Data\mark\bin\config\index.html C:\WINDOWS\system32\Temp\index.html C:\Data\HomeDir\index.html 

In the first call to Combine(), four parameters are specified. The second call contains only three parameters. In the final call, parameters are passed using an array. In other words, the Combine() method takes a variable number of parameters, whether separated by a comma or as a single array.

To allow this, the Combine() method

  1. Places params immediately before the last parameter in the method declaration

  2. Declares the last parameter as an array

With a parameter array declaration, it is possible to access each parameter as a member of the params array. In the Combine() method implementation, you iterate over the elements of the paths array and call System.IO.Path.Combine(). This method automatically combines the parts of the path, appropriately using the platform-specific directory-separator-character. (PathEx.Combine() is identical to Path.Combine(), except that PathEx.Combine() handles a variable number of parameters rather than simply two.)

There are a few notable characteristics of the parameter array.

  • The parameter array is not necessarily the only parameter on a method. However, the parameter array must be the last parameter in the method declaration. Since only the last parameter may be a parameter array, a method cannot have more than one parameter array.

  • The caller can specify zero parameters for the parameter array, which will result in an array of zero items.

  • Parameter arrays are type safethe type must match the type identified by the array.

  • The caller can use an explicit array rather than a comma-separated list of parameters. The resulting CIL code is identical.

  • If the target method implementation requires a minimum number of parameters, then those parameters should appear explicitly within the method declaration, forcing a compile error instead of relying on runtime error handling if required parameters are missing. For example, use int Max(int first, params int[] operads) rather than int Max(params int[] operads) so that at least one value is passed to Max().

Using a parameter array, you can pass a variable number of parameters of the same type into a method. The section Method Overloading, later in this chapter, discusses a means of supporting a variable number of parameters that are not necessarily of the same type.

Essential C# 2.0
Essential C# 2.0
ISBN: 0321150775
EAN: 2147483647
Year: 2007
Pages: 185 © 2008-2017.
If you may any questions please contact us: