0Pricing
C# Academy · レッスン

ジェネリックメソッド

メソッドの型パラメーターを学びます。

「ジェネリックメソッド」はCoddyKit上の無料C# Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC# Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C# Academyコースには全4レッスンが含まれています。

ジェネリックメソッドとは

ジェネリックメソッドは、独自の1つ以上の型パラメーターを宣言します。型パラメーターはメソッド名の後に山かっこで記述します。同じメソッド本体を、キャストや重複なしで複数の型に使用できます。

型パラメーターは T のようなプレースホルダーです。コンパイラーが呼び出し箇所で実際の型に置き換えるため、型安全性が保たれます。

void Print<T>(T value)
{
    Console.WriteLine(value);
}

型パラメーターの宣言

型パラメーターリスト <T> は、メソッド名とパラメーターリストの間に置きます。メソッド本体内では、T をパラメーターの型、戻り値の型、またはローカル変数の型として使用できます。

慣例として、型パラメーターが1つの場合は T という名前にします。TKey のような説明的な名前もよく使われます。

T Echo<T>(T input)
{
    return input;
}

型推論を使った呼び出し

通常、型引数を明示的に指定する必要はありません。コンパイラーは渡された引数から T を推論します。

ここでは、Echo(42) から T = int が推論され、Echo("hi") から T = string が推論されます。型推論により、ジェネリックメソッドの呼び出しを簡潔で読みやすく保てます。

using System;

class Program
{
    static T Echo<T>(T input) => input;

    static void Main()
    {
        Console.WriteLine(Echo(42));
        Console.WriteLine(Echo("hi"));
    }
}

型引数の明示的な指定

推論で型を決定できない場合や、型を明示したい場合は、呼び出し箇所で山かっこを使って型引数を指定します。

引数に型情報が含まれていない場合、たとえば T が戻り値の型にしか現れないメソッドでは、これが必要です。

T Create<T>() where T : new() => new T();

// call:
var list = Create<int>();

複数の型パラメーター

ジェネリックメソッドでは、コンマで区切って複数の型パラメーターを宣言できます。それぞれの型パラメーターは個別に推論することも、指定することもできます。

典型的な例として、異なる2つの型を扱うスワップやペア構築メソッドがあります。

(TSecond, TFirst) Flip<TFirst, TSecond>(TFirst a, TSecond b)
{
    return (b, a);
}

ジェネリックなスワップ

ジェネリックメソッドは、具体的な型を意識しないユーティリティで特に効果を発揮します。スワップでは、同じ型の任意の2つの値の順序を入れ替えられます。

ref キーワードを使うと、メソッドから呼び出し元の変数をその場で変更できます。

using System;

class Program
{
    static void Swap<T>(ref T a, ref T b)
    {
        T temp = a;
        a = b;
        b = temp;
    }

    static void Main()
    {
        int x = 1, y = 2;
        Swap(ref x, ref y);
        Console.WriteLine($"{x} {y}");
    }
}

メソッドパラメーターの制約

ジェネリックメソッドでは、where 句を使って型パラメーターに制約を付けられます。制約によって、T に対して許可される操作をコンパイラーに伝えます。

以下では、where T : IComparable<T> によって、メソッド本体で CompareTo を安全に呼び出せます。

T Max<T>(T a, T b) where T : IComparable<T>
{
    return a.CompareTo(b) >= 0 ? a : b;
}

非ジェネリッククラスのジェネリックメソッド

ジェネリックメソッドを含めるために、クラス自体がジェネリックである必要はありません。静的ユーティリティクラスには、ジェネリックメソッドがよく定義されます。

これにより、クラス全体に型パラメーターを持たせることなく、汎用的なヘルパーをまとめて管理できます。

static class Util
{
    public static T First<T>(T[] items) => items[0];
}

配列からの推論

型推論は、配列やコレクションを引数に渡す場合にも機能します。int[] を渡すと、T = int が自動的に推論されます。

これにより、ジェネリックアルゴリズムを組み込みの言語機能のように扱えます。

using System;

class Program
{
    static T First<T>(T[] items) => items[0];

    static void Main()
    {
        int[] nums = { 10, 20, 30 };
        Console.WriteLine(First(nums));
    }
}

object を使うだけではいけない理由

ジェネリックが登場する前は、object とキャストが使われていました。その場合、型安全性が失われ、値型がボックス化されるため、パフォーマンスも低下します。

ジェネリックメソッドを使えば、値型のボックス化を避けられ、実行時に例外を発生させるのではなく、コンパイル時に型の誤りを検出できます。

// Unsafe: needs a cast and can fail at runtime
object Echo(object o) => o;
int n = (int)Echo(5);

異なる型を返す

戻り値の型自体をジェネリックにすることもできるため、1つのメソッドで呼び出し元に合わせた出力を生成できます。default(T) は、値型の場合はゼロ値を、参照型の場合は null を返します。

値を取得できない場合の安全なフォールバックに便利です。

T OrDefault<T>(bool ok, T value)
{
    return ok ? value : default(T);
}

理解度チェック

ジェネリックメソッドについての理解度を確認しましょう。

まとめ

ジェネリックメソッドでは、名前の後ろの山かっこ内に独自の型パラメーターを宣言します。通常、コンパイラーは引数から型を推論しますが、明示的に指定することもできます。

ジェネリックメソッドは型安全性を保ち、ボックス化を避けられます。また、where 制約を付けることもできます。ジェネリックかどうかにかかわらず、任意のクラスに配置できます。

よくある質問

「ジェネリックメソッド」レッスンは無料ですか?

はい。「ジェネリックメソッド」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C# Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C# Academyコースには全4レッスンが含まれています。

「ジェネリックメソッド」で何を学びますか?

メソッドの型パラメーターを学びます。 ブラウザで直接実行するハンズオンコードでC# Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C# Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC# Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「ジェネリックメソッド」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC# Academyレッスンでコードを書いて実行できますか?

はい。すべてのC# Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ジェネリックメソッド
  2. ジェネリッククラス
  3. where制約
  4. ジェネリックインターフェース
← C# Academyに戻る