Subscribe

RSS Feed (xml)

Creating Simple Generic Method

As the preceding posts have shown, methods inside a generic class can make use of a class's type parameter and are, therefore, automatically generic relative to the type parameter. However, it is possible to declare a generic method that uses one or more type parameters of its own. Furthermore, it is possible to create a generic method that is enclosed within a non-generic class.

Let's begin with an example. The following program declares a non-generic class called ArrayUtils and a static generic method within that class called copyInsert( ). The copyInsert( ) method copies the contents of one array to another, inserting a new element at a specified location in the process. It can be used with any type of array.

// Demonstrate a generic method.

using System;

// A class of array utilities.  Notice that this is not
// a generic class.
class ArrayUtils {

  // Copy an array, inserting a new element
  // in the process.  This is a generic method.
  public static bool copyInsert<T>(T e, int idx,
                                   T[] src, T[] target) {

    // See if target array is big enough.
    if(target.Length < src.Length+1)
      return false;

    // Copy src to target, inserting e at idx in the process.
    for(int i=0, j=0; i < src.Length; i++, j++) {
      if(i == idx) {
        target[j] = e;
        j++;
      }
      target[j] = src[i];
    }

    return true;
  }
}

class GenMethDemo {
  public static void Main() {
    int[] nums = { 1, 2, 3 };
    int[] nums2 = new int[4];

    // Display contents of nums.
    Console.Write("Contents of nums: ");
    foreach(int x in nums)
      Console.Write(x + " ");

    Console.WriteLine();

    // Operate on an int array.
    ArrayUtils.copyInsert(99, 2, nums, nums2);

    // Display contents of nums2.
    Console.Write("Contents of nums2: ");
    foreach(int x in nums2)
      Console.Write(x + " ");

    Console.WriteLine();

    // Now, use copyInsert on an array of strings.
    string[] strs = { "Generics", "are", "powerful."};
    string[] strs2 = new string[4];

    // Display contents of strs.
    Console.Write("Contents of strs: ");
    foreach(string s in strs)
      Console.Write(s + " ");

    Console.WriteLine();

    // Insert into a string array.
    ArrayUtils.copyInsert("in C#", 1, strs, strs2);

    // Display contents of strs2.
    Console.Write("Contents of strs2: ");
    foreach(string s in strs2)
      Console.Write(s + " ");

    Console.WriteLine();

    // This call is invalid because the first argument
    // is of type double, and the third and fourth arguments
    // have base types of int.
//    ArrayUtils.copyInsert(0.01, 2, nums, nums2);

  }
}

The output from the program is shown here:

Contents of nums: 1 2 3
Contents of nums2: 1 2 99 3
Contents of strs: Generics are powerful.
Contents of strs2: Generics in C# are powerful.

Let's examine copyInsert( ) closely. First, notice how it is declared by this line:

public static bool copyInsert<T>(T e, int idx,
                                 T[] src, T[] target) {

The type parameter is declared after the method name, but before the parameter list. Also notice that copyInsert( ) is static, enabling it to be called independently of any object. Understand, though, that generic methods can be either static or non-static. There is no restriction in this regard.

Now, notice how copyInsert( ) is called within Main( ) by use of the normal call syntax, without the need to specify type arguments. This is because the types of the arguments are automatically discerned, and the type of T is adjusted accordingly. This process is called type inference. For example, in the first call:

ArrayUtils.copyInsert(99, 2, nums, nums2);

the type of T becomes int because 99 and the base types of nums and nums2 are int. In the second call, string types are used, and T is replaced by string.

Now, notice the commented-out code, shown here:

//    ArrayUtils.copyInsert(0.01, 2, nums, nums2);

If you remove the comment symbol and then try to compile the program, you will receive an error. The reason is that the type of the first argument is double, but the base types of nums and nums2 are int. However, all three types must be substituted for the same type parameter, T. This causes a type mismatch, which results in a compile-time error. This ability to enforce type safety is one of the most important advantages of generic methods.

The syntax used to create copyInsert( ) can be generalized. Here is the general form of a generic method:

ret-type meth-name<type-parameter-list>(param-list) { // ...

In all cases, type-parameter-list is a comma-separated list of type parameters. Notice that for a generic method, the type parameter list follows the method name.

No comments:

Post a Comment

Archives

LocalsAdda.com-Variety In Web World

Fun Mail - Fun in the Mail