C# Academy · レッスン

ジェネリックインターフェース

型に依存しない抽象化を行います。

レッスン 4/413 ステップ

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

ジェネリックインターフェイスとは

ジェネリックインターフェイスでは、名前の後ろの山かっこ内に型パラメーターを宣言します。実装する側が具体的な型を選択すると、それに応じてインターフェイスの契約も適応します。

.NET ライブラリでは、IEnumerable<T> や IComparable<T> など、ジェネリックインターフェイスが至るところで使われています。

interface IRepository<T>
{
    void Add(T item);
    T Get(int id);
}

ジェネリックインターフェイスの実装

クラスは、具体的な型引数を指定することでジェネリックインターフェイスを実装できます。すると、メソッドシグネチャではその実際の型を使用します。

これにより、キャストなしで型安全かつ再利用可能な契約を実現できます。

using System.Collections.Generic;

class IntStore : IRepository<int>
{
    private readonly List<int> data = new();
    public void Add(int item) => data.Add(item);
    public int Get(int id) => data[id];
}

interface IRepository<T>
{
    void Add(T item);
    T Get(int id);
}

実装側でジェネリックのままにする

クラスは、ジェネリックインターフェイスに独自の型パラメーターを渡しながら、自身もジェネリックのまま実装できます。

これにより、任意の要素型で実装を再利用できます。

using System.Collections.Generic;

class Store<T> : IRepository<T>
{
    private readonly List<T> data = new();
    public void Add(T item) => data.Add(item);
    public T Get(int id) => data[id];
}

interface IRepository<T> { void Add(T item); T Get(int id); }

IComparable<T> の実例

IComparable<T> は組み込みのジェネリックインターフェイスです。これを実装すると、型のインスタンスの順序を定義でき、並べ替えが可能になります。

CompareTo メソッドは、負の値、0、または正の値を返します。

class Money : IComparable<Money>
{
    public int Cents;
    public int CompareTo(Money? other)
        => Cents.CompareTo(other?.Cents ?? 0);
}

IEnumerable<T> の実装

IEnumerable<T> は、LINQ と foreach の中心となるインターフェイスです。これを実装する型は反復処理できます。多くの場合、内部コレクションのイテレーターに処理を委譲します。

yield return を使うイテレーターメソッドにより、簡単に実装できます。

using System.Collections;
using System.Collections.Generic;

class Bag<T> : IEnumerable<T>
{
    private readonly List<T> items = new();
    public void Add(T x) => items.Add(x);
    public IEnumerator<T> GetEnumerator() => items.GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

実行可能なジェネリックインターフェイス

この完全なプログラムでは、ジェネリックな IPrinter<T> を定義し、文字列用に実装してから使用します。

インターフェイスにより、具体的な型にかかわらず Print メソッドが保証されます。

using System;

interface IPrinter<T> { void Print(T value); }

class ConsolePrinter<T> : IPrinter<T>
{
    public void Print(T value) => Console.WriteLine(value);
}

class Program
{
    static void Main()
    {
        IPrinter<string> p = new ConsolePrinter<string>();
        p.Print("hello generics");
    }
}

out による共変性

out が付いたジェネリックインターフェイスの型パラメーターは共変です。これは出力位置にのみ現れます。これにより、IEnumerable<Cat> を IEnumerable<Animal> が必要な場所で使用できます。

共変性により、継承関係に沿った代入互換性が保たれます。

interface IProducer<out T>
{
    T Produce();
}

in による反変性

in が付いた型パラメーターは反変です。これは入力位置にのみ現れます。これにより、IComparer<Animal> を IComparer<Cat> が必要な場所で使用できます。

反変性により、コンシューマーに対する代入可能性の方向が反転します。

interface IConsumer<in T>
{
    void Consume(T item);
}

複数の型パラメーター

ジェネリックインターフェイスは、複数のパラメーターを受け取れます。IDictionary<TKey, TValue>は、キーの型と値の型を分けて指定する、よく知られた例です。

各パラメーターは、それぞれ独立して非変、共変、または反変にできます。

interface IMapper<TIn, TOut>
{
    TOut Map(TIn input);
}

インターフェイスに対してプログラミングする

具象クラスではなくジェネリックインターフェイスに依存すると、コードの柔軟性が高まります。呼び出し側を変更せずに実装を入れ替えられます。

IEnumerable<T>型のメソッドパラメーターは、リスト、配列、クエリ結果を同じように受け取れます。

using System.Collections.Generic;
using System.Linq;

int Total(IEnumerable<int> values) => values.Sum();

ジェネリックインターフェイスによる制約

ジェネリックインターフェイスは、制約として頻繁に使用されます。where T : IComparable<T>によって、メソッドで入力を並べ替えたり比較したりできます。

これは2つのジェネリック機能を組み合わせ、安全で再利用可能なアルゴリズムを実現します。

T Min<T>(T a, T b) where T : IComparable<T>
    => a.CompareTo(b) <= 0 ? a : b;

クイックチェック

ジェネリックインターフェイスについての理解度を確認しましょう。

まとめ

ジェネリックインターフェイスでは型パラメーターを宣言し、実装側でそれらを確定したり、そのまま引き継いだりできます。組み込みの例として、IEnumerable<T>、IComparable<T>、IDictionary<TKey, TValue>があります。

変性アノテーションのoutとinによって共変性と反変性を有効にでき、ジェネリックインターフェイスはwhere制約とも自然に組み合わせられます。

無料で開始

AI チューターと学ぶ C# — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
93
レッスン
346

よくある質問

「ジェネリックインターフェース」レッスンは無料ですか?

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

「ジェネリックインターフェース」で何を学びますか?

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

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

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

「ジェネリックインターフェース」レッスンにはどのくらい時間がかかりますか?

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

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

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

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

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