- 7.1 Introduction
- 7.2 Packaging Code in C#
- 7.3 static Methods, static Variables and Class Math
- 7.4 Methods with Multiple Parameters
- 7.5 Notes on Using Methods
- 7.6 Argument Promotion and Casting
- 7.7 The .NET Framework Class Library
- 7.8 Case Study: Random-Number Generation
- 7.9 Case Study: A Game of Chance; Introducing Enumerations
- 7.10 Scope of Declarations
- 7.11 Method-Call Stack and Activation Records
- 7.12 Method Overloading
- 7.13 Optional Parameters
- 7.14 Named Parameters
- 7.15 C# 6 Expression-Bodied Methods and Properties
- 7.16 Recursion
- 7.17 Value Types vs. Reference Types
- 7.18 Passing Arguments By Value and By Reference
- 7.19 Wrap-Up
7.4 Methods with Multiple Parameters
We now consider how to write a method with multiple parameters. Figure 7.2 defines Maximum method that determines and returns the largest of three double values. When the app begins execution, the Main method (lines 8–23) executes. Line 19 calls method Maximum (declared in lines 26–43) to determine and return the largest of its three double arguments. In Section 7.4.3, we’ll discuss the use of the + operator in line 22. The sample outputs show that Maximum determines the largest value regardless of whether that value is the first, second or third argument.
1 // Fig. 7.2: MaximumFinder.cs 2 // Method Maximum with three parameters. 3 using System; 4 5 class MaximumFinder 6 { 7 // obtain three floating-point values and determine maximum value 8 static void Main() 9 { 10 // prompt for and input three floating-point values 11 Console.Write("Enter first floating-point value: "); 12 double number1 = double.Parse(Console.ReadLine()); 13 Console.Write("Enter second floating-point value: "); 14 double number2 = double.Parse(Console.ReadLine()); 15 Console.Write("Enter third floating-point value: "); 16 double number3 = double.Parse(Console.ReadLine()); 17 18 // determine the maximum of three values 19 double result = Maximum(number1, number2, number3); 20 21 // display maximum value 22 Console.WriteLine("Maximum is: " + result); 23 } 24 25 // returns the maximum of its three double parameters 26 static double Maximum(double x, double y, double z) 27 { 28 double maximumValue = x; // assume x is the largest to start 29 30 // determine whether y is greater than maximumValue 31 if (y > maximumValue) 32 { 33 maximumValue = y; 34 } 35 36 // determine whether z is greater than maximumValue 37 if (z > maximumValue) 38 { 39 maximumValue = z; 40 } 41 42 return maximumValue; 43 } 44 }
Enter first floating-point values: 3.33 Enter second floating-point values: 1.11 Enter third floating-point values: 2.22 Maximum is: 3.33
Enter first floating-point values: 2.22 Enter second floating-point values: 3.33 Enter third floating-point values: 1.11 Maximum is: 3.33
Enter first floating-point values: 2.22 Enter second floating-point values: 1.11 Enter third floating-point values: 3.33 Maximum is: 3.33
Fig. 7.2 | Method Maximum with three parameters.
7.4.1 Keyword static
Method Maximum’s declaration begins with keyword static, which enables the Main method (another static method) to call Maximum as shown in line 19 without creating an object of class MaximumFinder and without qualifying the method name with the class name MaximumFinder—static methods in the same class can call each other directly.
7.4.2 Method Maximum
Consider the declaration of method Maximum (lines 26–43). Line 26 indicates that the method returns a double value, that the method’s name is Maximum and that the method requires three double parameters (x, y and z) to accomplish its task. When a method has more than one parameter, the parameters are specified as a comma-separated list. When Maximum is called in line 19, the parameter x is initialized with the value of the argument number1, the parameter y is initialized with the value of the argument number2 and the parameter z is initialized with the value of the argument number3. There must be one argument in the method call for each required parameter in the method declaration. Also, each argument must be consistent with the type of the corresponding parameter. For example, a parameter of type double can receive values like 7.35 (a double), 22 (an int) or –0.03456 (a double), but not strings like "hello". Section 7.6 discusses the argument types that can be provided in a method call for each parameter of a simple type. Note the use of type double’s Parse method in lines 12, 14 and 16 to convert into double values the strings typed by the user.
Logic of Determining the Maximum Value
To determine the maximum value, we begin with the assumption that parameter x contains the largest value, so line 28 declares local variable maximumValue and initializes it with the value of parameter x. Of course, it’s possible that parameter y or z contains the largest value, so we must compare each of these values with maximumValue. The if statement at lines 31–34 determines whether y is greater than maximumValue. If so, line 33 assigns y to maximumValue. The if statement at lines 37–40 determines whether z is greater than maximumValue. If so, line 39 assigns z to maximumValue. At this point, the largest of the three values resides in maximumValue, so line 42 returns that value to line 19 where it’s assigned to the variable result. When program control returns to the point in the app where Maximum was called, Maximum’s parameters x, y and z are no longer accessible. Methods can return at most one value; the returned value can be a value type that contains one or more values (implemented as a struct; Section 10.13) or a reference to an object that contains one or more values.
7.4.3 Assembling strings with Concatenation
C# allows string objects to be created by assembling smaller strings into larger strings using operator + (or the compound assignment operator +=). This is known as string concatenation. When both operands of operator + are string objects, the + operator creates a new string object containing copies of the characters in its left operand followed by copies of the characters in its right operand. For example, the expression "hello " + "there" creates the string "hello there" without disturbing the original strings.
In line 22, the expression "Maximum is: " + result uses operator + with operands of types string and double. Every simple-type value has a string representation. When one of the + operator’s operands is a string, the other is implicitly converted to a string, then the two strings are concatenated. So, in line 22, the double value is converted to its string representation and placed at the end of "Maximum is: ". If there are any trailing zeros in a double value, these are discarded. Thus, the string representation of 9.3500 is "9.35".
Anything Can Be Converted to a string
If a bool is concatenated with a string, the bool is converted to the string "True" or "False" (each is capitalized). In addition, every object has a ToString method that returns a string representation of that object. When an object is concatenated with a string, the object’s ToString method is called implicitly to obtain the string representation of the object. If the object is null, an empty string is written.
If a type does not define a ToString method, the default ToString implementation returns a string containing the type’s fully qualified name—that is, the namespace in which the type is defined followed by a dot (.) and the type name (e.g., System.Object for the .NET class Object). Each type you create can declare a custom ToString method, as you’ll do in Chapter 8 for a Card class that represents a playing card in a deck of cards.
Formatting strings with string Interpolation
Line 22 of Fig. 7.2, of course, could also be written using string interpolation as
Console.WriteLine($"Maximum is: {result}");
As with string concatenation, using string interpolation to insert an object into a string implicitly calls the object’s ToString method to obtain the object’s string representation.
7.4.4 Breaking Apart Large string Literals
When a large string literal or interpolated string is typed into an app’s source code, you can break that string into several smaller strings and place them on multiple lines for readability. The strings can be reassembled using string concatenation. We discuss the details of strings in Chapter 16.
7.4.5 When to Declare Variables as Fields
Variable result is a local variable in method Main because it’s declared in the block that represents the method’s body. Variables should be declared as fields of a class (i.e., as either instance variables or static variables) only if they’re required for use in more than one method of the class or if the app should save their values between calls to a given method.
7.4.6 Implementing Method Maximum by Reusing Method Math.Max
Recall from Fig. 7.1 that class Math’s Max method can determine the larger of two values. The entire body of our maximum method could also be implemented with nested calls to Math.Max, as follows:
return Math.Max(x, Math.Max(y, z));
The leftmost Math.Max call has the arguments x and Math.Max(y, z). Before any method can be called, the runtime evaluates all the arguments to determine their values. If an argument is a method call, the call must be performed to determine its return value. So, in the preceding statement, Math.Max(y, z) is evaluated first to determine the larger of y and z. Then the result is passed as the second argument to the first call to Math.Max, which returns the larger of its two arguments. Using Math.Max in this manner is a good example of software reuse—we find the largest of three values by reusing Math.Max, which finds the larger of two values. Note how concise this code is compared to lines 28–42 of Fig. 7.2.