isa*_*go_ 2 c# delegates covariance
它具有以下特点interface:
public interface ICovariant<out T>
{
public void InputFunc(Func<T> func);
}
Run Code Online (Sandbox Code Playgroud)
我收到以下编译时错误:
无效方差:协变类型参数“T”用于逆变位置。参数必须是输入安全的
输入Func<T>的位置。是,所以是输出。Func<T>Func<out T>
好吧,我错了。获取位置相关的信息。
但是,当我添加以下方法时,会发生错误。
public interface ICovariant<out T>
{
public void InputFunc(Func<T> func);
public Action<T> ReturnAction();
}
Run Code Online (Sandbox Code Playgroud)
无效方差:协变类型参数“T”用于逆变位置。方法返回类型必须是输出安全的
的位置Action<T>是输出。Action<T>是Action<in T>,所以输入。
什么?与之前不同的是,这次地点并不重要。
为什么这两个例子对彼此的看法不同?
Eri*_*ert 12
Sweeper接受的答案很好;我想提供一种稍微不同的方式来思考为什么你提出的计划是非法的。在此之前,请允许我再次对此处错误消息的低质量表示歉意。我想不出更好的办法,而且显然在接下来的 15 年里它们并没有得到太大的改进。
public interface ICovariant<out T>
{
public Action<T> ReturnAction(); // Why is this illegal?
}
Run Code Online (Sandbox Code Playgroud)
为什么这是非法的?尝试实施它,然后看看会出现什么问题!
class Animal {...}
class Mammal : Animal {...}
// ... and so on ...
class Danger: ICovariant<Mammal>
{
public Action<Mammal> ReturnAction()
{
return (Mammal m) => { m.ProduceMilk(); };
}
}
Run Code Online (Sandbox Code Playgroud)
Danger满足以下要求ICovariant<Mammal>——它返回一个动作,该动作需要一个哺乳动物,并且它做一件事——使哺乳动物产生牛奶:
ICovariant<Mammal> danger = new Danger();
Action<Mammal> action = danger.ReturnAction();
action(new Goat()); // Goat milk, mmmmm
Run Code Online (Sandbox Code Playgroud)
但ICovariant<Mammal>可以转换为,ICovariant<Animal>因为它是协变的,所以我们也可以写:
ICovariant<Animal> danger = new Danger();
// ICov<Animal> produces an Action<Animal>
Action<Animal> action = danger.ReturnAction();
action(new Chicken());
Run Code Online (Sandbox Code Playgroud)
现在我们已经给鸡挤了奶。这种尝试不会带来任何好处。
上面的行是完全合法的;它们不可能是错误。为了防止这种情况发生,编译器必须使接口本身非法。