Method Overloading


It is a basic object-oriented design principle that a method name should reflect what the method actually does. Often, several methods are required that do similar things, but accept different arguments. In some programming languages, convoluted method names such as PrintString(), PrintImage(), and Print() methods might be used to cope with this. In languages that target the .NET Framework, such as C#, we can call all of these methods by what they do: Print().

Overloading is used extensively within the .NET Framework base-class libraries and can be identified in the IntelliSense information displayed when coding a method call in Visual Studio .NET. The first version of the method is displayed with ‘1 of n’, followed by the method signature. The spinner controls, or the up-down arrow keys can be used to navigate to each version of the method.

Overloading is particularly useful in utility type classes, where a consistent approach of two (or more) variations on every method could be implemented. For example, we may have a class to abstract a data-access component. The class supports retrieving customers from the database using a GetCustomer() method. Two versions of this method could be coded to accept a customer ID as an int value, and the customer ID embedded in an XML node.

Overloading methods allows us to specify several variations of the same method all with the same name, and differing only by the method signature. The signature (sometimes referred to as prototype) of a method is the combination of both its name and its parameter list.

Below is a method, DisplayCalculatedCost(), which accepts two arguments: an Order object and a Double:

    private void DisplayCalculatedCost(Order order, double orderCost)    {      // Display the details    } 

This has the following signature:

    DisplayCalculatedCost(Order, Double) 

While the CalculateCost() method:

    private double CalculateCost(double orderCost, double deliveryFee)    {      // Calculate order cost    } 

has the following signature:

    CalculateCost(Double, Double) 

As you can see the return type is not considered part of the method's signature. This defines one of the rules of overloading:

Important

Two or more methods cannot overload each other if they differ only by return types.

Consider the signature resulting from a params argument type. As discussed earlier, the compiler creates a signature reference for each possible outcome of the function. In the case of a parameter array, this list is potentially infinite. This is demonstrated by:

    public static int AverageScores(params int[] scores)    {      int total = 0;      int average = 0;      foreach(int score in scores)      {        total += score;      }      average = total / scores.Length;      return average;    } 

resulting in the signatures:

    AverageScores(ref int)    AverageScores(ref int, ref int)    AverageScores(ref int, ref int, ref int)    ...and so on 

When you want to overload a method, a number of rules apply:

  • Each overload must differ by one (or more) of the following:

    • Parameter count

    • Parameter data types

    • Parameter order

  • Each method should use the same method name; otherwise, you are simply creating a totally new method.

  • You cannot overload a method with a property of the same name or vice versa.

You might be surprised to see that just changing the order of parameters overloads a method, as shown below (argument_order.cs):

    using System;    public class MethodOverload    {      public int Add(int number_one, double number_two)      {        return (int)(number_one + number_two);      }      public int Add(double number_two, int number_one)      {        return (int)(number_two - number_one);      }    }    public class Test    {      public static void Main(string[] args)      {        MethodOverload overload_meth = new MethodOverload();        Console.WriteLine("Add (int, double) "+ overload_meth.Add(4,3.2));        Console.WriteLine("Add (double, int) "+ overload_meth.Add(4.2,3));      }    } 

Here we have defined two methods called Add(), which both take two arguments, an int and a double. The only difference is the order in which the arguments are passed:

  • Add(int, double)

  • Add(double, int)

The first method really does add the numbers but the second subtracts them:

    C:\ClassDesign\Chapter03>argument_order    Add (int, double) 7    Add (double, int) 1 

Simply by switching the order in which we pass parameters we can call different methods. While you would never implement a design quite this bad, it does demonstrate that overloading methods by parameter order alone is usually a bad idea. It will make your code hard to read and people calling your methods will get confused.

Here is an example of overloading a function in a more useful manner:

    private double CalculateCost(double orderCost)    {      // Calculate total cost      return (this.CalculateCost(orderCost, 0, 0));    }    private double CalculateCost(double orderCost, double deliveryFee)    {      // Calculate total cost      return (this.CalculateCost(orderCost, deliveryFee, 0));    }    private double CalculateCost(double orderCost, double deliveryFee,                                 double handlingFee)    {      // Calculate total cost      return (orderCost + deliveryFee + handlingFee);    } 

These methods have the following finite signatures:

  • CalculateCost(Double)

  • CalculateCost(Double, Double)

  • CalculateCost(Double, Double, Double)

These methods calculate the cost of some goods with an optional delivery fee and handling charge. Notice the use of the this keyword to identify that we are calling the local version of the overloaded method. The first two methods call the third overload passing the appropriate number of zeros.

There are advantages of overloading methods. Method overloading should be used to provide different methods that do semantically the same thing. More than one method with the same name can be defined within a type as long as the signatures differ. You should always carefully consider whether giving two methods different names would create greater clarity in your class interface than creating two methods that only differ by their signatures. To use the Add() example we showed earlier, we could have several versions of this method that all took different types of number as arguments, so long as they all returned the sum of the two (or more) values passed in. Although if we were to create a method that concatenated strings, or combined non-numerical values, or worse did some mathematical operation on numbers other than adding them, it would be unwise to give it the same name.




C# Class Design Handbook(c) Coding Effective Classes
C# Class Design Handbook: Coding Effective Classes
ISBN: 1590592573
EAN: 2147483647
Year: N/A
Pages: 90

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net