連載:[完全版]究極のC#プログラミング

Chapter2 ジェネリック

川俣 晶
2009/08/17

2.6 ジェネリックメソッドと型推論

 ジェネリックは、クラス以外にも使用できる。構造体やインターフェースにも使用できるだけでなく、デリゲートやメソッドにも使用できる。

 ここでは、特にジェネリックを使用したメソッドである「ジェネリックメソッド」に注目しよう。これは、すぐに使える便利な機能であると同時に、注意を要する面もあるためだ。

 クラスライブラリが提供するジェネリックメソッドの中で、特に誰でも使う可能性があるのは、配列をソートするArrayクラスのSortメソッドだろう。使い方はクラスと同様、メソッドの名前の後ろに「<」と「>」で囲んだ型名を書くだけである(リスト2.6参照)。なお、リスト2.6には、出力される内容をコメントとして記してある(以降も、記述を簡明にするため、必要に応じ同様の方法をとる)。

using System;

class Program
{
  static void Main(string[] args)
  {
    int[] array = { 3, 2, 1 };
    Array.Sort<int>(array); // ジェネリックメソッドの呼び出し

    foreach (int i in array) Console.WriteLine(i);
    // 出力:
    // 1
    // 2
    // 3
  }
}
リスト2.6 ジェネリックメソッドの使用例

 <int>を指定したSort<int>メソッドは、引数にint型の配列を受け取り、その要素を昇順にソートするためのメソッドだ。

 しかし、このArray.Sortの後ろにある<int>という記述はあまり意味がない。なぜなら、引数に指定した変数arrayの型がint[]型である以上、通常、<int>以外を記述することはありえないからだ。

 そこで、「型の推論」という機能を使ってC#コンパイラに型を推理させることができる。この機能があるため、<int>を省いても意図どおりに動作する(リスト2.7参照)。

using System;

class Program
{
  static void Main(string[] args)
  {
    int[] array = { 3, 2, 1 };
    Array.Sort(array); // <int>を省略している

    foreach (int i in array) Console.WriteLine(i);
    // 出力:
    // 1
    // 2
    // 3
  }
}
リスト2.7 型の推論によってジェネリックメソッドを使う

 このコードは、一見しただけでは、C# 1.x時代のジェネリックメソッドでないSortメソッドの呼び出しと区別がつかない。しかし、ildasm*2や.NET Reflectorで実際に生成されたコードを見ると、ジェネリックではない従来版Sortメソッドではなく、型の推論が行われてSort<int>メソッドが呼び出されていることがわかるだろう。

 さて、型の推論は強力ではあるが、まれに型の推論を使えない場合もある。

 たとえば、異なるIComparableインターフェースを実装した基底クラスと派生クラスがある場合、それを明示的に使い分けなければ結果が変わってしまうことがある。実際にコーディングしたのが、次のリスト2.8である。

using System;

public class ClassA : IComparable<ClassA>
{
  public int Value;
  public ClassA(int v)
  {
    Value = v;
  }

  public int CompareTo(ClassA other)
  {
    return Value.CompareTo(other.Value);
  }
}

public class ClassB : ClassA, IComparable<ClassB>
{
  public ClassB(int v) : base (v) { }

  public int CompareTo(ClassB other)
  {
    return other.Value.CompareTo(Value);
  }
}

class Program
{
  static void Main(string[] args)
  {
    ClassB[] array = {
      new ClassB(3),
      new ClassB(2),
      new ClassB(1),
    };

    Array.Sort<ClassA>(array);
    foreach (ClassB b in array) Console.WriteLine(b.Value);
    // 出力:
    // 1
    // 2
    // 3

    Array.Sort<ClassB>(array);
    foreach (ClassB b in array) Console.WriteLine(b.Value);
    // 出力:
    // 3
    // 2
    // 1
  }
}
リスト2.8 型の推論が使えない例

 このプログラムにおいて、型の指定を省略して「Array.Sort(array);」と記述すると「Array.Sort<ClassB>(array);」と推論されるが、その実行結果は「Array.Sort<ClassA>(array);」の実行結果とは異なるものになる。

*2 ildasmはマイクロソフトより提供される逆アセンブラ。Visual Studio等をインストールすると標準でインストールされる。


 INDEX
  [完全版]究極のC#プログラミング
  Chapter2 ジェネリック
    1.2.1 ジェネリックとは何か?
    2.2.2 新しいコレクションの紹介
    3.2.3 新しいコレクションクラス―LinkedListクラス
    4.2.4 新しいコレクションクラス―SortedDictionaryクラス
    5.2.5 ジェネリックコレクションの使い方
  6.2.6 ジェネリックメソッドと型推論
    7.2.7 HashtableクラスとDictionaryクラスの非互換性
    8.2.8 ジェネリックなクラスを自作する
    9.2.9 制約の付いたジェネリックなクラス/C++のtemplate機能との相違/練習問題
 
インデックス・ページヘ  「[完全版]究極のC#プログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間