Поделиться через


Ковариантность и контравариантность (C#)

В C#ковариация и контравариантность обеспечивают неявное преобразование ссылок для типов массивов, типов делегатов и аргументов универсального типа. Ковариация сохраняет совместимость назначений и контравариантность изменяет ее.

В следующем коде показано различие между совместимостью назначений, ковариантностью и контравариантностью.

// Assignment compatibility.
string str = "test";  
// An object of a more derived type is assigned to an object of a less derived type.
object obj = str;  
  
// Covariance.
IEnumerable<string> strings = new List<string>();  
// An object that is instantiated with a more derived type argument
// is assigned to an object instantiated with a less derived type argument.
// Assignment compatibility is preserved.
IEnumerable<object> objects = strings;  
  
// Contravariance.
// Assume that the following method is in the class:
static void SetObject(object o) { }
Action<object> actObject = SetObject;  
// An object that is instantiated with a less derived type argument
// is assigned to an object instantiated with a more derived type argument.
// Assignment compatibility is reversed.
Action<string> actString = actObject;  

Ковариация для массивов обеспечивает неявное преобразование массива более производного типа в массив менее производного типа. Но эта операция не является безопасной, как показано в следующем примере кода.

object[] array = new String[10];  
// The following statement produces a run-time exception.  
// array[0] = 10;  

Поддержка ковариации и контравариации для групп методов позволяет сопоставлять сигнатуры методов с типами делегатов. Это позволяет назначать делегатам не только методы, имеющие соответствующие сигнатуры, но и методы, возвращающие более производные типы (ковариантность) или принимающие параметры, имеющие менее производные типы (контравариантность), чем указанные типом делегата. Дополнительные сведения см. в разделах "Вариативность в делегатах (C#)" и "Использование вариативности в делегатах (C#)".

В следующем примере кода показана поддержка ковариации и контравариации для групп методов.

static object GetObject() { return null; }  
static void SetObject(object obj) { }  
  
static string GetString() { return ""; }  
static void SetString(string str) { }  
  
static void Test()  
{  
    // Covariance. A delegate specifies a return type as object,  
    // but you can assign a method that returns a string.  
    Func<object> del = GetString;  
  
    // Contravariance. A delegate specifies a parameter type as string,  
    // but you can assign a method that takes an object.  
    Action<string> del2 = SetObject;  
}  

В .NET Framework 4 и более поздних версиях C# поддерживает ковариацию и контравариацию в универсальных интерфейсах и делегатах и позволяет неявное преобразование параметров универсального типа. Для получения дополнительной информации см. раздел "Вариативность в универсальных интерфейсах (C#)" и "Вариативность в делегатах (C#)".

В следующем примере кода показано неявное преобразование ссылок для универсальных интерфейсов.

IEnumerable<String> strings = new List<String>();  
IEnumerable<Object> objects = strings;  

Универсальный интерфейс или делегат называется вариантом , если его универсальные параметры объявлены ковариантными или контравариантными. C# позволяет создавать собственные вариантные интерфейсы и делегаты. Для получения дополнительной информации см. раздел Создание вариантных универсальных интерфейсов (C#) и Вариантность в делегатах (C#).

Название Описание
Вариативность в универсальных интерфейсах (C#) Обсуждает ковариантность и контравариантность в универсальных интерфейсах и предоставляет список вариантов универсальных интерфейсов в .NET.
Создание вариантных универсальных интерфейсов (C#) Показывает, как создавать интерфейсы пользовательских вариантов.
Использование дисперсии в интерфейсах для универсальных коллекций (C#) Показывает, как поддержка ковариации и контравариации в IEnumerable<T>IComparable<T> интерфейсах помогает повторно использовать код.
Вариативность в делегатах (C#) Обсуждает ковариантность и контравариантность в универсальных и не универсальных делегатах и предоставляет список вариантов универсальных делегатов в .NET.
Использование дисперсии в делегатах (C#) Показывает, как использовать поддержку ковариации и контравариации в необобщённых делегатах для соответствия подписей методов типам делегатов.
Использование вариативности для func и универсальных делегатов действий (C#) Показывает, как поддержка ковариации и контравариации в Func и Action делегатах может помочь повторно использовать код.