C# 汎用ジェネリック・デリゲートの共変性と反変性

C#

.NET Framework 3.5以降、デリゲートでも変性がサポートされています。つまりメソッドのパラメータや戻り値で派生型(共変)や基本型(反変)との互換性がサポートされます。ここではFunc 汎用デリゲートにおける共変性と Action 汎用デリゲートの反変性についてまとめます。

サンプルコードの前提

Cat型はAnimal型を継承しており、CatはAnimalに代入可能、暗黙でキャストされます。

Cat <: Animal

    class Animal { public void DoSomething() { /****/ }  }
    class Cat : Animal { }

汎用デリゲートの共変性

汎用ジェネリックデリゲート Funcでは戻り値の互換性が共変性を持っています。

    static void Main(string[] args)
    {
        Cat GetCat(string name) { return new Cat(name); }
        Func<string, Animal> fAnimal = GetCat;
        Cat cat = GetCat("Chatra");
        cat.WriteLine();
        //
        Func<string, Cat> FCat = GetCat;
    }

fAnimalの宣言は、Func<string, Animal>となっており、Animalを戻り値として想定していますが、Catを戻り値の型とするメソッドGetCatを代入できます。

Func<Cat> >: Func<Animal>

汎用のジェネリック・デリゲートFuncの定義はTResult Func<in T, out TResult>(T arg) となっており、戻り値TResultがout指定のため共変性を持つことができます。

汎用デリゲートの反変性

汎用ジェネリックActionでは、引数パラメーターの互換性が反変性を持ちます。

    class Animal { public void DoSomething() { /****/ }  }
    class Cat : Animal { }

    static void Main(string[] args)
    {
        void SetAnimal(Animal a) { a.DoSomething(); }
        Action<Cat> actToCat = SetAnimal;

        Action<Animal> actToAnimal = (a) => a.DoSomething();
        actToCat = actToAnimal;
        //
        actToCat(new Cat());
    }

actToCatの宣言はAction<Cat>となっており、引数にクラスCatを想定していますが、クラスAnimalを引数として定義されたメソッドSetAnimalを代入できます。

また、actToCatに対して、Action<Animal>型を宣言したactToAnimalを直接代入することもできます。

型パラメータである Cat <: Animal に対して反変性を持ちます。Action<Animal> <: Action<Cat>

参照

共変性と反変性 (C#)
共変性と反変性、およびそれらが割り当ての互換性に与える影響について説明します。 両者の違いを示すコード例を参照してください。

コメント

タイトルとURLをコピーしました