Ковариация и контравариантность (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 и Action (C#) | Узнайте, как использовать поддержку ковариации и контрвариантности в делегатах Func и Action для многократного использования кода. |