它有以下interface项:

public interface ICovariant<out T>
{
    public void InputFunc(Func<T> func);
}

我得到以下编译时错误:

无效的差异:协变类型参数‘T’用于逆变位置.参数必须是输入安全的

Func<T>的位置是input.Func<T>等于Func<out T>,所以是output.

好吧,我错了.获取位置相关的信息.

但是,当我添加以下方法时,出现错误.

public interface ICovariant<out T>
{
    public void InputFunc(Func<T> func);
    public Action<T> ReturnAction();
}

无效的差异:协变类型参数‘T’用于逆变位置.方法返回类型必须是输出安全的

Action<T>的位置是output.Action<T>等于Action<in T>,所以是input.

什么?与以前不同的是,这一次,地点并不重要.

为什么这两个例子对彼此的看法不同?

推荐答案

与以前不同的是,这一次,地点并不重要.

位置does很重要!它完美地汇编了以下内容:

public interface ICovariant<out T>
{
    public void AcceptAction(Action<T> action);
}

Action中的逆变量类型参数所做的是,它使其相应的类型参数具有您放置它的位置的opposite位置-如果它最初在输入位置,它现在在输出位置,如果它最初在输出位置,它现在在输入位置.

"Contra-"的意思是"相反的",所以很容易记住这种行为:d尽管这种特殊的行为可能不是"反变异"这个名字的由来.Eric Lippert's answer here解释了它为什么叫这个名字.

因此,这也进行了编译(T的位置被"翻转"了两次,因此它回到了输出位置):

public Action<Action<T>> ReturnsNestedAction();

如果你只是想一想你实际上是如何callReturnAction的,你应该能够直观地说服自己,确实,Tin ReturnActionis处于输入位置:

Action<T> action = someICovariant.ReturnAction();
action(someT); // I am *inputting* an instance of T here!

同样,您可以对AcceptAction执行相同的操作,并看到T确实位于那里的输出位置:

someICovariant.AcceptAction(t => {
    Console.WriteLine(t);
});
/*
Imagine the implementation of AcceptAction invoking its parameter at some point.
That is analogous to AcceptAction *returning* some instance of T and we print it out
The difference being that instead of "return someT;", 
AcceptAction would do "action(someT);", but the fact it is producing an instance of T
doesn't change
*/

如果您对如何在技术术语中指定这一点感兴趣,您可以阅读this section of the language specification.

另请参阅这related question条关于声明逆变量类型参数时的类似"翻转位置"行为.

Csharp相关问答推荐

在2D数组中绘制椭圆

在WPF.NET 6中使用C++/WinRT组件(但实际上是任何WinRT组件)

ASP.NET MVC中创建视图的过滤器

如果存在对CodeAnalysis.CSharp的引用,则不能引用netStandard2.0库

使用命令初始化可绑定属性

ASP.NET Core 8.0 JWT验证问题:尽管令牌有效,但SecurityTokenNoExpirationError异常

使页面内容居中

将现有字段映射到EFCore中的复杂类型

Rx.Net窗口内部可观测数据提前完成

NET8 MAUI并部署到真实设备上进行测试

C#Null判断处理失败

具有可空类型的C#NOTNULL约束具有意外行为

避免只读记录 struct 中的防御副本

是否由DI容器自动处理由ActivatorUilties.CreateInstance()创建的服务?

有条件地定义预处理器指令常量

如何返回具有泛型的类?

MudBlazor Textfield已禁用,但其验证工作正常

数据库操作预计影响1行,但实际影响0行; after _dbContext.SaveChanges();

用于分钟和秒验证的MudTextfield的正则表达式掩码

在c#中,使用Okta和Blazor时,LocalReDirect()陷入循环,出现错误&请求太多.