- 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.12 Method Overloading
Methods of the same name can be declared in the same class, as long as they have different sets of parameters (determined by the number, types and order of the parameters). This is called method overloading. When an overloaded method is called, the C# compiler selects the appropriate method by examining the number, types and order of the arguments in the call. Method overloading is commonly used to create several methods with the same name that perform the same or similar tasks, but on different types or different numbers of arguments. For example, Random method Next (Section 7.8) has overloads that accept different numbers of arguments, and Math method Max has overloads that accept different types of arguments (ints vs. doubles). These find the minimum and maximum, respectively, of two values of each of the numeric simple types. Our next example demonstrates declaring and invoking overloaded methods. You’ll see examples of overloaded constructors in Chapter 10.
7.12.1 Declaring Overloaded Methods
In class MethodOverload (Fig. 7.13), we include two Square methods—one that calculates the square of an int (and returns an int) and one that calculates the square of a double (and returns a double). Although these methods have the same name and similar parameter lists and bodies, you can think of them simply as different methods. It may help to think of the method names as “Square of int” and “Square of double,” respectively.
1 // Fig. 7.13: MethodOverload.cs 2 // Overloaded method declarations. 3 using System; 4 5 class MethodOverload 6 { 7 // test overloaded square methods 8 static void Main() 9 { 10 Console.WriteLine($"Square of integer 7 is {Square(7)}"); 11 Console.WriteLine($"Square of double 7.5 is {Square(7.5)}"); 12 } 13 14 // square method with int argument 15 static int Square(int intValue) 16 { 17 Console.WriteLine($"Called square with int argument: {intValue}"); 18 return intValue * intValue; 19 } 20 21 // square method with double argument 22 static double Square(double doubleValue) 23 { 24 Console.WriteLine( 25 $"Called square with double argument: {doubleValue}"); 26 return doubleValue * doubleValue; 27 } 28 }
Called square with int argument: 7 Square of integer 7 is 49 Called square with double argument: 7.5 Square of double 7.5 is 56.25
Fig. 7.13 | Overloaded method declarations.
Line 10 in Main invokes method Square with the argument 7. Literal integer values are treated as type int, so the method call in line 10 invokes the version of Square at lines 15–19 that specifies an int parameter. Similarly, line 11 invokes method Square with the argument 7.5. Literal real-number values are treated as type double, so the method call in line 11 invokes the version of Square at lines 22–27 that specifies a double parameter. Each method first outputs a line of text to prove that the proper method was called in each case.
The overloaded methods in Fig. 7.13 perform the same calculation, but with two different types. C#’s generics feature provides a mechanism for writing a single “generic method” that can perform the same tasks as an entire set of overloaded methods. We discuss generic methods in Chapter 18.
7.12.2 Distinguishing Between Overloaded Methods
The compiler distinguishes overloaded methods by their signature—a combination of the method’s name and the number, types and order of its parameters. The signature also includes the way those parameters are passed, which can be modified by the ref and out keywords (discussed in Section 7.18). If the compiler looked only at method names during compilation, the code in Fig. 7.13 would be ambiguous—the compiler would not know how to distinguish between the Square methods (lines 15–19 and 22–27). Internally, the compiler uses signatures to determine whether a class’s methods are unique in that class.
For example, in Fig. 7.13, the compiler will use the method signatures to distinguish between the “Square of int” method (the Square method that specifies an int parameter) and the “Square of double” method (the Square method that specifies a double parameter). As another example, if Method1’s declaration begins as
void Method1(int a, float b)
then that method will have a different signature than a method that begins with
void Method1(float a, int b)
The order of the parameter types is important—the compiler considers the preceding two Method1 headers to be distinct.
7.12.3 Return Types of Overloaded Methods
In discussing the logical names of methods used by the compiler, we did not mention the methods’ return types. Methods cannot be distinguished by return type. If in a class named MethodOverloadError you define overloaded methods with the following headers:
int Square(int x) double Square(int x)
which each have the same signature but different return types, the compiler generates the following error for the second Square method:
Type 'MethodOverloadError' already defines a member called 'Square' with the same parameter types
Overloaded methods can have the same or different return types if the parameter lists are different. Also, overloaded methods need not have the same number of parameters.