方差示例(Jon Skeet 书)[已关闭]

问题描述 投票:0回答:1

书中第二个例子的方向是从动态到对象,对吗?第一个示例具有从字符串到对象的方向,我认为第二个示例将从对象到动态。

为了将其转化为具体示例,让我们考虑一下

Func<in T, out TResult>
。规则含义如下:

  1. 存在从

    Func<object, int>
    Func<string, int>
    的有效转换,因为

    • 第一个类型参数是逆变的,并且存在隐式引用转换从字符串到对象
    • 第二个类型参数是协变的,并且存在从 int 到 int 的恒等转换。
  2. 存在从

    Func<dynamic, string>
    Func<object, IConvertible>
    的有效转换,因为

    • 第一个类型参数是逆变的,并且存在从动态到对象的恒等转换
    • 第二个类型参数是协变的,并且存在从字符串到 IConvertible 的隐式引用转换

代码片段取自 J. Skeet 所著的《C# in Depth》第四版,第 147 页。

c# covariance contravariance
1个回答
4
投票

逆变

为了简单起见,我们考虑委托仅采用参数:

Action<in TParam>
。我们可以将其视为一种方法:

void SomeMethod(TParam param);

或更具体地说:

void SomeMethod(string param);

因此,将此类方法分配给变量是完全有效的,例如并调用它:

Action<string> action = SomeMethod;
action("some value");

现在,让我们考虑一下

action
变量 - 它接受字符串参数,但是如果该变量引用
Action<object>
呢?如下:

// Note changed type of param
void SomeMethod(object param);

Action<string> action = SomeMethod;
// IMPORTANT - this is still perfectly valid
action("some value");

它仍然可以工作,因为

action
被声明为仅接受
string
的方法,因此只要
string
派生自,那么底层的内容(什么是 true 类型参数)并不真正让我们担心那种类型。

这就是逆变的全部内容,直线

Action<string> action = SomeMethod;
如果

SomeMethod

 的参数具有 
object
 类型,则 
仍然有效。

协方差

更简单。为了简单起见,让我们考虑一下

Func<out TResult>

TResult
是委托的返回类型。因此,如果方法返回
object
,它也可以返回较少的派生类型,并且结果仍然可以分配给基本类型,即:

Func<object> d1 = () => new object();
Func<string> d2 = () => "covariance";

现在,当你调用

d1()
时,你期望得到一个对象,当你调用
d2()
时,你期望得到一个字符串。由于
string
派生自
object
,如果该方法返回更多派生类型(例如字符串),
d1
的调用者不会中断。所以作业:

d1 = d2;

可以工作,因为返回类型仍然兼容。

这要归功于协方差(另一个例子可能是集合)。

把它们放在一起

我希望很清楚,现在

Func<TInput, TResult>
和其他代表(具有更多类型参数)只是我上面解释的一些组合:)

回到你的问题。

Func
委托中的第一个类型参数(当有两个以上类型参数时)是逆变的(带有
in
修饰符)。这意味着派生较少的类型可以分配给使用派生较多的类型定义的变量。所以:

  1. Func<object, int>
    Func<string, int>
    - 正确,因为
    Func<object, int>
    可以分配给任何
    Func<whatever, int>
    ,因为
    whatever
    源自
    object

  2. Func<dynamic, string>
    Func<object, IConvertible>
    - 正确,因为
    Func<dynamic, int>
    可以分配给任何
    Func<object, int>
    ,因为
    object
    可以分配给
    dynamic

© www.soinside.com 2019 - 2024. All rights reserved.