Action的通用约束无法按预期工作

Jim*_*ies 9 .net c# generics covariance contravariance

我无法理解为什么以下代码段不会给我一个错误

public void SomeMethod<T>(T arg) where T : MyInterface
{
  MyInterface e = arg;
}
Run Code Online (Sandbox Code Playgroud)

但是这个,我期望由于泛型类型约束而工作

private readonly IList<Action<MyInterface>> myActionList = new List<Action<MyInterface>>();

public IDisposable Subscribe<T>(Action<T> callback) where T: MyInterface
{
  myActionList.Add(callback); // doesn't compile
  return null
}
Run Code Online (Sandbox Code Playgroud)

给出了这个错误

cannot convert from 'System.Action<T>' to 'System.Action<MyInterface>'
Run Code Online (Sandbox Code Playgroud)

我正在使用VS2012 sp1和.NET 4.5.

任何人都可以解释为什么约束不允许这个编译?

Lee*_*Lee 5

这是一个逆变问题-一个Action<MyInterface>应该能够采取任何MyInterface实例作为论据,但是你想存储的Action<T>地方T是一些亚型MyInterface,这是不是安全的.

例如,如果你有:

public class SomeImpl : MyInterface { }
public class SomeOtherImpl : MyInterface { }
List<Action<MyInterface>> list;

list.Add(new Action<SomeImpl>(i => { }));
ActionMyInterface act = list[0];
act(new SomeOtherImpl());
Run Code Online (Sandbox Code Playgroud)

如果类型比类型"小",则只能指定Action<T>一些.例如Action<U>TU

Action<string> act = new Action<object>(o => { });
Run Code Online (Sandbox Code Playgroud)

是安全的,因为字符串参数在对象参数所在的位置始终有效.


ody*_*jii 3

类和代表不是同一件事。System.Action<MyInterface>表示具有类型 的单个参数的函数MyInterface,而System.Action<T>表示具有类型 的参数的方法T : MyInterfaceT函数签名不兼容,与 的导数无关,只有在完全是 的情况MyInterface下签名才兼容。TMyInterface