CSharp-变体

Show you the code.[1][2][3][4]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// Variant type parameters could be declared in interfaces or delegates only!

interface ICovariant<out T>
{
}

class Covariant<T> : ICovariant<T>
{
}

interface IContravariant<in T>
{
}

class Contravariant<T> : IContravariant<T>
{
}

interface IInvariant<T>
{
}

class Invariant<T> : IInvariant<T>
{
}

class Program
{
private static void Covariant( /* out */)
{
ICovariant<object> obj = new Covariant<object>();
ICovariant<string> str = new Covariant<string>();

// You can assign "Derived" to "Base"
obj = str;
str = obj; // error
}

private static void Contravariant( /* in */)
{
IContravariant<object> obj = new Contravariant<object>();
IContravariant<string> str = new Contravariant<string>();

// You can assign "Base" to "Derived"
str = obj;
obj = str; // error
}

private static void Invariant( /* none */)
{
IInvariant<object> obj = new Invariant<object>();
IInvariant<string> str = new Invariant<string>();

// You can't do any assign
obj = str; // error
str = obj; // error
}
}

  1. Microsoft Learn, Covariance and Contravariance in Generics 与 C# language specification §19.2.3 Variant type parameter lists 支撑:C# 的变体类型参数只出现在接口和委托类型上,并通过 in / out 标注协变、逆变或不变。 ↩︎

  2. Microsoft Learn out generic modifier 说明 out 表示协变类型参数,允许把更派生的类型实参作为更宽泛的泛型接口或委托使用;这对应示例里 ICovariant<string> 可赋值给 ICovariant<object>↩︎

  3. Microsoft Learn in generic modifier 说明 in 表示逆变类型参数,允许把更宽泛的类型实参作为更具体的泛型接口或委托使用;这对应示例里 IContravariant<object> 可赋值给 IContravariant<string>↩︎

  4. Microsoft Learn Creating Variant Generic Interfaces 与 C# language specification 的 variance conversion 规则共同支撑:未标注 in / out 的类型参数是不变的,变体转换需要满足对应的协变、逆变或恒等转换条件。 ↩︎