Method Usage Guidelines

The following rules outline the usage guidelines for methods:

  • Choose a name for your event based on the recommended Method Naming Guidelines.
  • Do not use Hungarian notation.
  • By default, methods are nonvirtual. Maintain this default in situations where it is not necessary to provide virtual methods. For more information about implementing inheritance, see Base Class Usage Guidelines.

Method Overloading Guidelines

Method overloading occurs when a class contains two methods with the same name, but different signatures. This section provides some guidelines for the use of overloaded methods.

  • Use method overloading to provide different methods that do semantically the same thing.

  • Use method overloading instead of allowing default arguments. Default arguments do not version well and therefore are not allowed in the Common Language Specification (CLS). The following code example illustrates an overloaded String.IndexOf method.

    Function String.IndexOf(name As String) As Integer
    Function String.IndexOf(name As String, startIndex As Integer) As Integer
    [C#]
    int String.IndexOf (String name);
    int String.IndexOf (String name, int startIndex);
    
  • Use default values correctly. In a family of overloaded methods, the complex method should use parameter names that indicate a change from the default state assumed in the simple method. For example, in the following code, the first method assumes the search will not be case-sensitive. The second method uses the name ignoreCase rather than caseSensitive to indicate how the default behavior is being changed.

    ' Method #1: ignoreCase = false.
    Function Type.GetMethod(name As String) As MethodInfo
    ' Method #2: Indicates how the default behavior of method #1 
    ' is being changed.
    Function Type.GetMethod(name As String, ignoreCase As Boolean) As MethodInfo
    [C#]
    // Method #1: ignoreCase = false.
    MethodInfo Type.GetMethod(String name); 
    // Method #2: Indicates how the default behavior of method #1 is being // changed.
     MethodInfo Type.GetMethod (String name, Boolean ignoreCase);
    
  • Use a consistent ordering and naming pattern for method parameters. It is common to provide a set of overloaded methods with an increasing number of parameters to allow the developer to specify a desired level of information. The more parameters that you specify, the more detail the developer can specify. In the following code example, the overloaded Execute method has a consistent parameter order and naming pattern variation. Each of the Execute method variations uses the same semantics for the shared set of parameters.

    Public Class SampleClass
       Private defaultForA As String = "default value for a"
       Private defaultForB As Integer = "42"
       Private defaultForC As Double = "68.90"
    
       Overloads Public Sub Execute()
          Execute(defaultForA, defaultForB, defaultForC)
       End Sub
    
       Overloads Public Sub Execute(a As String)
          Execute(a, defaultForB, defaultForC)
       End Sub
    
       Overloads Public Sub Execute(a As String, b As Integer)
          Execute(a, b, defaultForC)
       End Sub
    
       Overloads Public Sub Execute(a As String, b As Integer, c As Double)
          Console.WriteLine(a)
          Console.WriteLine(b)
          Console.WriteLine(c)
          Console.WriteLine()
       End Sub 
    End Class
    [C#]
    public class SampleClass
    {
       readonly string defaultForA = "default value for a";
       readonly int defaultForB = "42";
       readonly double defaultForC = "68.90";
    
       public void Execute()
       {
          Execute(defaultForA, defaultForB, defaultForC);
       }
    
       public void Execute (string a)
       {
          Execute(a, defaultForB, defaultForC);
       }
    
       public void Execute (string a, int b)
       {
          Execute (a, b, defaultForC);     
       }
    
       public void Execute (string a, int b, double c)
       {
          Console.WriteLine(a);
          Console.WriteLine(b);
          Console.WriteLine(c);
          Console.WriteLine();
       } 
    }
    

    Note that the only method in the group that should be virtual is the one that has the most parameters and only when you need extensibility.

  • If you must provide the ability to override a method, make only the most complete overload virtual and define the other operations in terms of it. The following example illustrates this pattern.

    Public Class SampleClass
       Private myString As String
    
       Public Sub New(str As String)
          Me.myString = str
       End Sub
    
       Overloads Public Function IndexOf(s As String) As Integer
          Return IndexOf(s, 0)
       End Function
    
       Overloads Public Function IndexOf(s As String, startIndex As 
                Integer) As Integer
          Return IndexOf(s, startIndex, myString.Length - startIndex)
       End Function
    
       Overloads Public Overridable Function IndexOf(s As String, 
                startIndex As Integer, count As Integer) As Integer
          Return myString.IndexOf(s, startIndex, count)
       End Function 
    End Class
    [C#]
    public class SampleClass
    {
       private string myString;
    
       public MyClass(string str)
       {
          this.myString = str;
       }
    
       public int IndexOf(string s) 
       {
          return IndexOf (s, 0);
       }
    
       public int IndexOf(string s, int startIndex) 
       {
          return IndexOf(s, startIndex, myString.Length - startIndex );
       }
    
       public virtual int IndexOf(string s, int startIndex, int count) 
       {
          return myString.IndexOf(s, startIndex, count);
       }
    }
    

Methods With Variable Numbers of Arguments

You might want to expose a method that takes a variable number of arguments. A classic example is the printf method in the C programming language. For managed class libraries, use the params (ParamArray in Visual Basic) keyword for this construct. For example, use the following code instead of several overloaded methods.

Sub Format(formatString As String, ParamArray args() As Object)
[C#]
void Format(string formatString, params object [] args)

You should not use the VarArgs or ellipsis (...) calling convention exclusively because the Common Language Specification does not support it.

For extremely performance-sensitive code, you might want to provide special code paths for a small number of elements. You should only do this if you are going to special case the entire code path (not just create an array and call the more general method). In such cases, the following pattern is recommended as a balance between performance and the cost of specially cased code.

Sub Format(formatString As String, arg1 As Object)
Sub Format(formatString As String, arg1 As Object, arg2 As Object)

Sub Format(formatString As String, ParamArray args() As Object)
[C#]
void Format(string formatString, object arg1)
void Format(string formatString, object arg1, object arg2)
   
void Format(string formatString, params object [] args)

See Also

Design Guidelines for Class Library Developers | Method Naming Guidelines | Class Member Usage Guidelines | Base Class Usage Guidelines