ジェネリックの共変性と反変性Covariance and Contravariance in Generics

共変性と反変性は、元の指定よりも強い派生型 (具体性が高い) と弱い派生型 (具体性が低い) を使用する能力を示す用語です。Covariance and contravariance are terms that refer to the ability to use a more derived type (more specific) or a less derived type (less specific) than originally specified. ジェネリック型パラメーターは、ジェネリック型の代入と使用の柔軟性を向上させるために、共変性と反変性をサポートしています。Generic type parameters support covariance and contravariance to provide greater flexibility in assigning and using generic types. 型システムにおいて、共変性、反変性、および不変性は、次のように定義されます。When you are referring to a type system, covariance, contravariance, and invariance have the following definitions. 各例では、基底クラスが Base という名前であり、派生クラスが Derivedという名前であるとします。The examples assume a base class named Base and a derived class named Derived.

  • Covariance

    最初に指定された型よりも強い派生型を使用できるようにします。Enables you to use a more derived type than originally specified.

    IEnumerable<Derived> (Visual Basic では IEnumerable(Of Derived)) のインスタンスを IEnumerable<Base> 型の変数に割り当てることができます。You can assign an instance of IEnumerable<Derived> (IEnumerable(Of Derived) in Visual Basic) to a variable of type IEnumerable<Base>.

  • Contravariance

    最初に指定された型よりも一般的な (弱い派生の) 型を使用できるようにします。Enables you to use a more generic (less derived) type than originally specified.

    Action<Base> (Visual Basic ではAction(Of Base) ) のインスタンスを Action<Derived>型の変数に割り当てることができます。You can assign an instance of Action<Base> (Action(Of Base) in Visual Basic) to a variable of type Action<Derived>.

  • Invariance

    最初に指定された型のみを使用できることを意味します。そのため、不変のジェネリック型パラメーターは、共変でも反変でもありません。Means that you can use only the type originally specified; so an invariant generic type parameter is neither covariant nor contravariant.

    List<Base> (Visual Basic では List(Of Base)) のインスタンスを List<Derived> 型の変数に割り当てることはできず、その逆もできません。You cannot assign an instance of List<Base> (List(Of Base) in Visual Basic) to a variable of type List<Derived> or vice versa.

共変の型パラメーターでは、次のコードで示されているように、通常のポリモーフィズムと非常によく似た代入を行うことができます。Covariant type parameters enable you to make assignments that look much like ordinary Polymorphism, as shown in the following code.

IEnumerable<Derived> d = new List<Derived>();
IEnumerable<Base> b = d;
Dim d As IEnumerable(Of Derived) = New List(Of Derived)
Dim b As IEnumerable(Of Base) = d

List<T> クラスは IEnumerable<T> インターフェイスを実装するため、 List<Derived> (Visual Basic ではList(Of Derived) ) は IEnumerable<Derived>を実装します。The List<T> class implements the IEnumerable<T> interface, so List<Derived> (List(Of Derived) in Visual Basic) implements IEnumerable<Derived>. 共変の型パラメーターが後の処理を行います。The covariant type parameter does the rest.

一方、反変性は直感に反するように見えます。Contravariance, on the other hand, seems counterintuitive. 次の例では、 Action<Base> 型 (Visual Basic ではAction(Of Base) ) のデリゲートを作成し、次にそのデリゲートを Action<Derived>型の変数に代入します。The following example creates a delegate of type Action<Base> (Action(Of Base) in Visual Basic), and then assigns that delegate to a variable of type Action<Derived>.

Action<Base> b = (target) => { Console.WriteLine(target.GetType().Name); };
Action<Derived> d = b;
d(new Derived());
Dim b As Action(Of Base) = Sub(target As Base) 
                               Console.WriteLine(target.GetType().Name)
                           End Sub
Dim d As Action(Of Derived) = b
d(New Derived())

これは逆方向のように見えますが、コンパイルして実行できるタイプ セーフ コードです。This seems backward, but it is type-safe code that compiles and runs. ラムダ式は代入先のデリゲートに一致するため、 Base 型のパラメーターを 1 つ受け取って戻り値を返さないメソッドを定義します。The lambda expression matches the delegate it is assigned to, so it defines a method that takes one parameter of type Base and that has no return value. Action<Derived> デリゲートの型パラメーター T は反変であるため、結果として得られたデリゲートは Action<T> 型の変数に代入できます。The resulting delegate can be assigned to a variable of type Action<Derived> because the type parameter T of the Action<T> delegate is contravariant. T はパラメーター型を指定するため、コードはタイプ セーフです。The code is type-safe because T specifies a parameter type. Action<Base> 型のデリゲートが Action<Derived>型のデリゲートであるかのように呼び出される場合、その引数は Derived型である必要があります。When the delegate of type Action<Base> is invoked as if it were a delegate of type Action<Derived>, its argument must be of type Derived. メソッドのパラメーターは Base型であるため、この引数は、基になるメソッドに常に安全に渡すことができます。This argument can always be passed safely to the underlying method, because the method's parameter is of type Base.

一般に、共変の型パラメーターはデリゲートの戻り値の型として使用でき、反変の型パラメーターはパラメーター型として使用できます。In general, a covariant type parameter can be used as the return type of a delegate, and contravariant type parameters can be used as parameter types. インターフェイスについては、共変の型パラメーターをインターフェイスのメソッドの戻り値の型として使用でき、反変の型パラメーターをインターフェイスのメソッドのパラメーター型として使用できます。For an interface, covariant type parameters can be used as the return types of the interface's methods, and contravariant type parameters can be used as the parameter types of the interface's methods.

共変性と反変性は、"分散" と総称されます。Covariance and contravariance are collectively referred to as variance. 共変または反変としてマークされていないジェネリック型パラメーターは、 不変と呼ばれます。A generic type parameter that is not marked covariant or contravariant is referred to as invariant. 共通言語ランタイムにおける分散について、簡潔な概要を示します。A brief summary of facts about variance in the common language runtime:

  • .NET Framework 4 のバリアント型パラメーターは、ジェネリック インターフェイス型と汎用デリゲート型に制限されています。In the .NET Framework 4, variant type parameters are restricted to generic interface and generic delegate types.

  • ジェネリック インターフェイス型や汎用デリゲート型では、共変と反変の両方の型パラメーターを使用できます。A generic interface or generic delegate type can have both covariant and contravariant type parameters.

  • 分散が適用されるのは参照型のみです。バリアント型パラメーターに対して値型を指定すると、その型パラメーターが、結果の構築型で不変になります。Variance applies only to reference types; if you specify a value type for a variant type parameter, that type parameter is invariant for the resulting constructed type.

  • 変性は、デリゲートの組み合わせには適用されません。Variance does not apply to delegate combination. つまり、 Action<Derived> 型と Action<Base> 型 (Visual Basic ではAction(Of Derived)Action(Of Base) ) の 2 つのデリゲートがある場合、結果はタイプ セーフになりますが、2 つ目のデリゲートに 1 つ目のデリゲートを組み合わせることはできません。That is, given two delegates of types Action<Derived> and Action<Base> (Action(Of Derived) and Action(Of Base) in Visual Basic), you cannot combine the second delegate with the first although the result would be type safe. 変性によって 2 つ目のデリゲートを Action<Derived>型の変数に代入できますが、デリゲートを組み合わせることができるのは、それらの型が完全に一致している場合だけです。Variance allows the second delegate to be assigned to a variable of type Action<Derived>, but delegates can combine only if their types match exactly.

以降では、共変と反変の型パラメーターについて詳しく説明します。The following subsections describe covariant and contravariant type parameters in detail:

共変の型パラメーターを持つジェネリック インターフェイスGeneric Interfaces with Covariant Type Parameters

.NET Framework 4 以降には、共変の型パラメーターを持つジェネリック インターフェイスがいくつかあります (IEnumerable<T>IEnumerator<T>IQueryable<T>IGrouping<TKey,TElement> など)。Starting with the .NET Framework 4, several generic interfaces have covariant type parameters; for example: IEnumerable<T>, IEnumerator<T>, IQueryable<T>, and IGrouping<TKey,TElement>. これらのインターフェイスのすべての型パラメーターは共変のみであるため、型パラメーターはメンバーの戻り値の型だけに使用されます。All the type parameters of these interfaces are covariant, so the type parameters are used only for the return types of the members.

共変の型パラメーターの例を以下に示します。The following example illustrates covariant type parameters. ここでは 2 つの型が定義されています。 Base には、 PrintBases (Visual Basic では IEnumerable<Base> ) を受け取って要素を出力するIEnumerable(Of Base) という静的メソッドがあります。The example defines two types: Base has a static method named PrintBases that takes an IEnumerable<Base> (IEnumerable(Of Base) in Visual Basic) and prints the elements. DerivedBaseを継承します。Derived inherits from Base. この例は、空の List<Derived> (Visual Basic ではList(Of Derived) ) を作成し、その型を PrintBases に渡して、キャストすることなく、 IEnumerable<Base> 型の変数に代入できることを示しています。The example creates an empty List<Derived> (List(Of Derived) in Visual Basic) and demonstrates that this type can be passed to PrintBases and assigned to a variable of type IEnumerable<Base> without casting. List<T> は、共変の型パラメーターを 1 つ持つ IEnumerable<T>を実装します。List<T> implements IEnumerable<T>, which has a single covariant type parameter. IEnumerable<Derived> のインスタンスを IEnumerable<Base>の代わりに使用できるのは、この共変の型パラメーターがあるためです。The covariant type parameter is the reason why an instance of IEnumerable<Derived> can be used instead of IEnumerable<Base>.

using System;
using System.Collections.Generic;

class Base
{
    public static void PrintBases(IEnumerable<Base> bases)
    {
        foreach(Base b in bases)
        {
            Console.WriteLine(b);
        }
    }
}

class Derived : Base
{
    public static void Main()
    {
        List<Derived> dlist = new List<Derived>();

        Derived.PrintBases(dlist);
        IEnumerable<Base> bIEnum = dlist;
    }
}
Imports System.Collections.Generic

Class Base
    Public Shared Sub PrintBases(ByVal bases As IEnumerable(Of Base))
        For Each b As Base In bases
            Console.WriteLine(b)
        Next
    End Sub    
End Class

Class Derived
    Inherits Base

    Shared Sub Main()
        Dim dlist As New List(Of Derived)()

        Derived.PrintBases(dlist)
        Dim bIEnum As IEnumerable(Of Base) = dlist
    End Sub
End Class

ページのトップへBack to top

反変のジェネリック型パラメーターを持つジェネリック インターフェイスGeneric Interfaces with Contravariant Generic Type Parameters

.NET Framework 4 以降には、反変の型パラメーターを持つジェネリック インターフェイスがいくつかあります (IComparer<T>IComparable<T>IEqualityComparer<T> など)。Starting with the .NET Framework 4, several generic interfaces have contravariant type parameters; for example: IComparer<T>, IComparable<T>, and IEqualityComparer<T>. これらのインターフェイスの型パラメーターは反変のみであるため、これらの型パラメーターは、インターフェイスのメンバーのパラメーター型としてのみ使用されます。These interfaces have only contravariant type parameters, so the type parameters are used only as parameter types in the members of the interfaces.

反変の型パラメーターの例を以下に示します。The following example illustrates contravariant type parameters. この例では、MustInherit プロパティを使用して抽象 (Visual Basic では Shape ) Area クラスを定義しています。The example defines an abstract (MustInherit in Visual Basic) Shape class with an Area property. また、 ShapeAreaComparer (Visual Basic では IComparer<Shape> ) を実装するIComparer(Of Shape) クラスを定義しています。The example also defines a ShapeAreaComparer class that implements IComparer<Shape> (IComparer(Of Shape) in Visual Basic). IComparer<T>.Compare メソッドの実装は Area プロパティの値に基づくため、 ShapeAreaComparer を使用して、領域で Shape オブジェクトを並べ替えることができます。The implementation of the IComparer<T>.Compare method is based on the value of the Area property, so ShapeAreaComparer can be used to sort Shape objects by area.

Circle クラスは Shape を継承し、 Areaをオーバーライドします。The Circle class inherits Shape and overrides Area. この例では、 SortedSet<T> (Visual Basic では Circle ) を受け取るコンストラクターを使用して、 IComparer<Circle> オブジェクトのIComparer(Of Circle) を作成します。The example creates a SortedSet<T> of Circle objects, using a constructor that takes an IComparer<Circle> (IComparer(Of Circle) in Visual Basic). ただし、 IComparer<Circle>を渡す代わりに、 ShapeAreaComparer を実装する IComparer<Shape>オブジェクトを渡します。However, instead of passing an IComparer<Circle>, the example passes a ShapeAreaComparer object, which implements IComparer<Shape>. この例では、Shapeジェネリック インターフェイスの型パラメーターは反変であるため、コードがより強い派生型 (Circle) の比較子を要求している場合に、より弱い派生型 ( IComparer<T> ) の比較子を渡すことができます。The example can pass a comparer of a less derived type (Shape) when the code calls for a comparer of a more derived type (Circle), because the type parameter of the IComparer<T> generic interface is contravariant.

新しい Circle オブジェクトを SortedSet<Circle>に追加すると、新しい要素が既存の要素と比較されるたびに IComparer<Shape>.Compare オブジェクトのIComparer(Of Shape).Compare メソッド (Visual Basic では ShapeAreaComparer メソッド) が呼び出されます。When a new Circle object is added to the SortedSet<Circle>, the IComparer<Shape>.Compare method (IComparer(Of Shape).Compare method in Visual Basic) of the ShapeAreaComparer object is called each time the new element is compared to an existing element. このメソッドのパラメーターの型 (Shape) は、渡される型 (Circle) より弱い派生型なので、この呼び出しはタイプ セーフです。The parameter type of the method (Shape) is less derived than the type that is being passed (Circle), so the call is type safe. 反変性により、 ShapeAreaComparer で、単一の型のコレクションおよび Shapeから派生した型の混合コレクションを並べ替えることができるようになります。Contravariance enables ShapeAreaComparer to sort a collection of any single type, as well as a mixed collection of types, that derive from Shape.

using System;
using System.Collections.Generic;

abstract class Shape
{
    public virtual double Area { get { return 0; }}
}

class Circle : Shape
{
    private double r;
    public Circle(double radius) { r = radius; }
    public double Radius { get { return r; }}
    public override double Area { get { return Math.PI * r * r; }}
}

class ShapeAreaComparer : System.Collections.Generic.IComparer<Shape>
{
    int IComparer<Shape>.Compare(Shape a, Shape b) 
    { 
        if (a == null) return b == null ? 0 : -1;
        return b == null ? 1 : a.Area.CompareTo(b.Area);
    }
}

class Program
{
    static void Main()
    {
        // You can pass ShapeAreaComparer, which implements IComparer<Shape>,
        // even though the constructor for SortedSet<Circle> expects 
        // IComparer<Circle>, because type parameter T of IComparer<T> is
        // contravariant.
        SortedSet<Circle> circlesByArea = 
            new SortedSet<Circle>(new ShapeAreaComparer()) 
                { new Circle(7.2), new Circle(100), null, new Circle(.01) };

        foreach (Circle c in circlesByArea)
        {
            Console.WriteLine(c == null ? "null" : "Circle with area " + c.Area);
        }
    }
}

/* This code example produces the following output:

null
Circle with area 0.000314159265358979
Circle with area 162.860163162095
Circle with area 31415.9265358979
 */
Imports System.Collections.Generic

MustInherit Class Shape
    Public MustOverride ReadOnly Property Area As Double
End Class

Class Circle
    Inherits Shape

    Private r As Double 
    Public Sub New(ByVal radius As Double)
        r = radius
    End Sub 
    Public ReadOnly Property Radius As Double
        Get
            Return r
        End Get
    End Property
    Public Overrides ReadOnly Property Area As Double
        Get
            Return Math.Pi * r * r
        End Get
    End Property
End Class

Class ShapeAreaComparer
    Implements System.Collections.Generic.IComparer(Of Shape)

    Private Function AreaComparer(ByVal a As Shape, ByVal b As Shape) As Integer _
            Implements System.Collections.Generic.IComparer(Of Shape).Compare
        If a Is Nothing Then Return If(b Is Nothing, 0, -1)
        Return If(b Is Nothing, 1, a.Area.CompareTo(b.Area))
    End Function
End Class

Class Program
    Shared Sub Main()
        ' You can pass ShapeAreaComparer, which implements IComparer(Of Shape),
        ' even though the constructor for SortedSet(Of Circle) expects 
        ' IComparer(Of Circle), because type parameter T of IComparer(Of T)
        ' is contravariant.
        Dim circlesByArea As New SortedSet(Of Circle)(New ShapeAreaComparer()) _
            From { New Circle(7.2), New Circle(100), Nothing, New Circle(.01) }

        For Each c As Circle In circlesByArea
            Console.WriteLine(If(c Is Nothing, "Nothing", "Circle with area " & c.Area))
        Next
    End Sub
End Class

' This code example produces the following output:
'
'Nothing
'Circle with area 0.000314159265358979
'Circle with area 162.860163162095
'Circle with area 31415.9265358979

ページのトップへBack to top

バリアント型パラメーターを持つ汎用デリゲートGeneric Delegates with Variant Type Parameters

.NET Framework 4 には、Func<T,TResult> などの Func 汎用デリゲートに、共変の戻り値の型と反変のパラメーターの型があります。In the .NET Framework 4, the Func generic delegates, such as Func<T,TResult>, have covariant return types and contravariant parameter types. Action などの Action<T1,T2>汎用デリゲートには、反変のパラメーターの型があります。The Action generic delegates, such as Action<T1,T2>, have contravariant parameter types. したがって、より強い派生型のパラメーターと、より弱い派生型の戻り値 ( Func 汎用デリゲートの場合) を持つ変数に、デリゲートを代入できます。This means that the delegates can be assigned to variables that have more derived parameter types and (in the case of the Func generic delegates) less derived return types.

注意

Func 汎用デリゲートの最後のジェネリック型パラメーターは、デリゲート シグネチャの戻り値の型を指定します。The last generic type parameter of the Func generic delegates specifies the type of the return value in the delegate signature. 他のジェネリック型パラメーターは反変 (out キーワード) ですが、この最後のジェネリック型パラメーターは共変 (in キーワード) です。It is covariant (out keyword), whereas the other generic type parameters are contravariant (in keyword).

次に例を示します。The following code illustrates this. コードの最初の部分では、 Baseという名前のクラスと、 Derived を継承する Baseという名前のクラスを定義しています。その他に、 static という名前のShared (Visual Basic では MyMethod) メソッドを持つクラスも定義されています。The first piece of code defines a class named Base, a class named Derived that inherits Base, and another class with a static method (Shared in Visual Basic) named MyMethod. このメソッドは、Base のインスタンスを受け取り、Derived のインスタンスを返しますThe method takes an instance of Base and returns an instance of Derived. (引数が Derived のインスタンスの場合は、それが MyMethod によって返されます。引数が Base のインスタンスの場合は、MyMethod によって Derived の新しいインスタンスが返されます)。Main() では、Func<Base, Derived> を表す Func(Of Base, Derived) (Visual Basic では MyMethod) のインスタンスを作成して、変数 f1 に格納しています。(If the argument is an instance of Derived, MyMethod returns it; if the argument is an instance of Base, MyMethod returns a new instance of Derived.) In Main(), the example creates an instance of Func<Base, Derived> (Func(Of Base, Derived) in Visual Basic) that represents MyMethod, and stores it in the variable f1.

public class Base {}
public class Derived : Base {}

public class Program
{
    public static Derived MyMethod(Base b)
    {
        return b as Derived ?? new Derived();
    }

    static void Main() 
    {
        Func<Base, Derived> f1 = MyMethod;
Public Class Base 
End Class
Public Class Derived
    Inherits Base
End Class

Public Class Program
    Public Shared Function MyMethod(ByVal b As Base) As Derived 
        Return If(TypeOf b Is Derived, b, New Derived())
    End Function

    Shared Sub Main() 
        Dim f1 As Func(Of Base, Derived) = AddressOf MyMethod

コードの 2 番目の部分は、このデリゲートを Func<Base, Base> (Visual Basic ではFunc(Of Base, Base) ) 型の変数に代入できることを示しています。これは、戻り値の型が共変であるためです。The second piece of code shows that the delegate can be assigned to a variable of type Func<Base, Base> (Func(Of Base, Base) in Visual Basic), because the return type is covariant.

// Covariant return type.
Func<Base, Base> f2 = f1;
Base b2 = f2(new Base());
' Covariant return type.
Dim f2 As Func(Of Base, Base) = f1
Dim b2 As Base = f2(New Base())

コードの 3 番目の部分は、このデリゲートを Func<Derived, Derived> (Visual Basic ではFunc(Of Derived, Derived) ) 型の変数に代入できることを示しています。これは、パラメーターの型が反変であるためです。The third piece of code shows that the delegate can be assigned to a variable of type Func<Derived, Derived> (Func(Of Derived, Derived) in Visual Basic), because the parameter type is contravariant.

// Contravariant parameter type.
Func<Derived, Derived> f3 = f1;
Derived d3 = f3(new Derived());
' Contravariant parameter type.
Dim f3 As Func(Of Derived, Derived) = f1
Dim d3 As Derived = f3(New Derived())

コードの最後の部分は、このデリゲートを Func<Derived, Base> (Visual Basic ではFunc(Of Derived, Base) ) 型の変数に代入できることを示しています。これは、反変のパラメーターの型と共変の戻り値の型の両方の効果の組み合わせによるものです。The final piece of code shows that the delegate can be assigned to a variable of type Func<Derived, Base> (Func(Of Derived, Base) in Visual Basic), combining the effects of the contravariant parameter type and the covariant return type.

// Covariant return type and contravariant parameter type.
Func<Derived, Base> f4 = f1;
Base b4 = f4(new Derived());
' Covariant return type and contravariant parameter type.
Dim f4 As Func(Of Derived, Base) = f1
Dim b4 As Base = f4(New Derived())

汎用デリゲートと非汎用デリゲートの変性Variance in Generic and Non-Generic Delegates

上のコードでは、 MyMethod のシグネチャが、構築された汎用デリゲート Func<Base, Derived> (Visual Basic ではFunc(Of Base, Derived) ) のシグネチャと厳密に一致しています。In the preceding code, the signature of MyMethod exactly matches the signature of the constructed generic delegate: Func<Base, Derived> (Func(Of Base, Derived) in Visual Basic). この例から、より強い派生型のパラメーターとより弱い派生型の戻り値を持つ変数やメソッド パラメーターにこの汎用デリゲートを格納できることと、そのためには、すべてのデリゲート型が汎用デリゲート型 Func<T,TResult>から構築されている必要があることがわかります。The example shows that this generic delegate can be stored in variables or method parameters that have more derived parameter types and less derived return types, as long as all the delegate types are constructed from the generic delegate type Func<T,TResult>.

これは重要なポイントです。This is an important point. 汎用デリゲートの型パラメーターにおける共変性と反変性の効果は、通常のデリゲート バインディングにおける共変性と反変性の効果 (「デリゲートの分散 (C#)」および「デリゲートの分散 (Visual Basic)」を参照) に似ていますが、The effects of covariance and contravariance in the type parameters of generic delegates are similar to the effects of covariance and contravariance in ordinary delegate binding (see Variance in Delegates (C#) and Variance in Delegates (Visual Basic)). デリゲート バインディングの分散は、バリアント型パラメーターを持つ汎用デリゲート型だけでなく、すべてのデリゲート型で使用できます。However, variance in delegate binding works with all delegate types, not just with generic delegate types that have variant type parameters. さらに、デリゲート バインディングの分散では、より限定的なパラメーターの型とより限定的でない戻り値の型を持つ任意のデリゲートにメソッドをバインドできますが、汎用デリゲートの代入を使用できるのは、両方のデリゲート型が同じジェネリック型定義から構築されている場合のみです。Furthermore, variance in delegate binding enables a method to be bound to any delegate that has more restrictive parameter types and a less restrictive return type, whereas the assignment of generic delegates works only if both delegate types are constructed from the same generic type definition.

デリゲート バインディングの分散とジェネリック型パラメーターの分散の両方の効果を組み合わせた例を以下に示します。The following example shows the combined effects of variance in delegate binding and variance in generic type parameters. ここでは、3 つの型を含む型階層を定義しています。Type1が最も弱い派生型で、Type3が最も強い派生型です。The example defines a type hierarchy that includes three types, from least derived (Type1) to most derived (Type3). 通常のデリゲート バインディングの分散を使用して、パラメーターの型が Type1 で戻り値の型が Type3 のメソッドを、パラメーターの型が Type2 で戻り値の型が Type2の汎用デリゲートにバインドしています。Variance in ordinary delegate binding is used to bind a method with a parameter type of Type1 and a return type of Type3 to a generic delegate with a parameter type of Type2 and a return type of Type2. その結果、得られた汎用デリゲートを、ジェネリック型パラメーターの共変性と反変性を使用して、 Type3 型のパラメーターと Type1型の戻り値を持つ汎用デリゲート型の変数に代入しています。The resulting generic delegate is then assigned to another variable whose generic delegate type has a parameter of type Type3 and a return type of Type1, using the covariance and contravariance of generic type parameters. 2 回目の代入では、変数型とデリゲート型の両方が同じジェネリック型定義 (この場合は Func<T,TResult>) から構築されている必要があります。The second assignment requires both the variable type and the delegate type to be constructed from the same generic type definition, in this case, Func<T,TResult>.

using System;

public class Type1 {}
public class Type2 : Type1 {}
public class Type3 : Type2 {}

public class Program
{
    public static Type3 MyMethod(Type1 t)
    {
        return t as Type3 ?? new Type3();
    }

    static void Main() 
    {
        Func<Type2, Type2> f1 = MyMethod;

        // Covariant return type and contravariant parameter type.
        Func<Type3, Type1> f2 = f1;
        Type1 t1 = f2(new Type3());
    }
}
Public Class Type1 
End Class
Public Class Type2
    Inherits Type1
End Class
Public Class Type3
    Inherits Type2
End Class

Public Class Program
    Public Shared Function MyMethod(ByVal t As Type1) As Type3
        Return If(TypeOf t Is Type3, t, New Type3())
    End Function

    Shared Sub Main() 
        Dim f1 As Func(Of Type2, Type2) = AddressOf MyMethod

        ' Covariant return type and contravariant parameter type.
        Dim f2 As Func(Of Type3, Type1) = f1
        Dim t1 As Type1 = f2(New Type3())
    End Sub
End Class

ページのトップへBack to top

バリアント ジェネリック インターフェイスとバリアント汎用デリゲートの定義Defining Variant Generic Interfaces and Delegates

.NET Framework 4 以降では、Visual Basic と C# の両方で、インターフェイスやデリゲートのジェネリック型パラメーターを共変または反変としてマークするためのキーワードが提供されています。Starting with the .NET Framework 4, Visual Basic and C# have keywords that enable you to mark the generic type parameters of interfaces and delegates as covariant or contravariant.

注意

ジェネリック型パラメーターの分散注釈は .NET Framework Version 2.0 以降の共通言語ランタイムでサポートされていますが、Starting with the .NET Framework version 2.0, the common language runtime supports variance annotations on generic type parameters. .NET Framework 4 より前で、これらの注釈を含むジェネリック クラスを定義するには、クラスを Ilasm.exe (IL Assembler) を使ってコンパイル、またはそれを動的アセンブリに出力することで、Microsoft Intermediate Language (MSIL) を使用する方法しかありませんでした。Prior to the .NET Framework 4, the only way to define a generic class that has these annotations is to use Microsoft intermediate language (MSIL), either by compiling the class with Ilasm.exe (IL Assembler) or by emitting it in a dynamic assembly.

共変の型パラメーターをマークするには、 out キーワード (Visual Basic ではOut キーワード、 + MSIL アセンブラー では) を使用します。A covariant type parameter is marked with the out keyword (Out keyword in Visual Basic, + for the MSIL Assembler). 共変の型パラメーターは、インターフェイスに属するメソッドの戻り値として使用したり、デリゲートの戻り値の型として使用したりできます。You can use a covariant type parameter as the return value of a method that belongs to an interface, or as the return type of a delegate. インターフェイス メソッドのジェネリック型制約として使用することはできません。You cannot use a covariant type parameter as a generic type constraint for interface methods.

注意

インターフェイスのメソッドに汎用デリゲート型のパラメーターがある場合は、インターフェイス型の共変の型パラメーターを使用してデリゲート型の反変の型パラメーターを指定できます。If a method of an interface has a parameter that is a generic delegate type, a covariant type parameter of the interface type can be used to specify a contravariant type parameter of the delegate type.

反変の型パラメーターをマークするには、 in キーワード (Visual Basic ではIn キーワード、 - MSIL アセンブラー では) を使用します。A contravariant type parameter is marked with the in keyword (In keyword in Visual Basic, - for the MSIL Assembler). 反変の型パラメーターは、インターフェイスに属するメソッドのパラメーターの型として使用したり、デリゲートのパラメーターの型として使用したりできます。You can use a contravariant type parameter as the type of a parameter of a method that belongs to an interface, or as the type of a parameter of a delegate. インターフェイス メソッドのジェネリック型制約として使用することもできます。You can use a contravariant type parameter as a generic type constraint for an interface method.

バリアント型パラメーターを持つことができるのは、インターフェイス型とデリゲート型だけです。Only interface types and delegate types can have variant type parameters. インターフェイス型やデリゲート型は、共変と反変の両方の型パラメーターを持つことができます。An interface or delegate type can have both covariant and contravariant type parameters.

Visual Basic と C# では、共変および反変の型パラメーターの使用規則に違反したり、インターフェイスとデリゲート以外の型の型パラメーターに共変性や反変性の注釈を追加したりすることは許可されません。Visual Basic and C# do not allow you to violate the rules for using covariant and contravariant type parameters, or to add covariance and contravariance annotations to the type parameters of types other than interfaces and delegates. MSIL アセンブラー ではそのようなチェックは行われませんが、規則に違反する型を読み込もうとすると TypeLoadException がスローされます。The MSIL Assembler does not perform such checks, but a TypeLoadException is thrown if you try to load a type that violates the rules.

詳細およびコード例については、「ジェネリック インターフェイスの分散 (C#)」および「ジェネリック インターフェイスの分散 (Visual Basic)」を参照してください。For information and example code, see Variance in Generic Interfaces (C#) and Variance in Generic Interfaces (Visual Basic).

ページのトップへBack to top

バリアント ジェネリック インターフェイス型とバリアント汎用デリゲート型の一覧List of Variant Generic Interface and Delegate Types

.NET Framework 4 では、次のインターフェイス型およびデリゲート型に、共変または反変、またはその両方の型パラメーターが含まれます。In the .NET Framework 4, the following interface and delegate types have covariant and/or contravariant type parameters.

Type 共変の型パラメーターCovariant type parameters 反変の型パラメーターContravariant type parameters
Action<T>Action<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16>Action<T> to Action<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16> はいYes
Comparison<T> はいYes
Converter<TInput,TOutput> はいYes はいYes
Func<TResult> はいYes
Func<T,TResult>Func<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,TResult>Func<T,TResult> to Func<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,TResult> はいYes はいYes
IComparable<T> はいYes
Predicate<T> はいYes
IComparer<T> はいYes
IEnumerable<T> はいYes
IEnumerator<T> はいYes
IEqualityComparer<T> はいYes
IGrouping<TKey,TElement> はいYes
IOrderedEnumerable<TElement> はいYes
IOrderedQueryable<T> はいYes
IQueryable<T> はいYes

関連項目See also