为什么C#out泛型类型参数违反协方差?

Mer*_*OWA 12 c# out covariance

我不清楚为什么下面的代码片段不是covarient?

  public interface IResourceColl<out T> : IEnumerable<T> where T : IResource {

    int Count { get; }

    T this[int index] { get; }

    bool TryGetValue( string SUID, out T obj ); // Error here?
    }
Run Code Online (Sandbox Code Playgroud)

错误1无效方差:类型参数"T"必须在'IResourceColl.TryGetValue(string,out T)'上不变地有效.'T'是协变的.

我的界面仅在输出位置使用模板参数.我可以轻松地将此代码重构为类似的东西

  public interface IResourceColl<out T> : IEnumerable<T> where T : class, IResource {

    int Count { get; }

    T this[int index] { get; }

    T TryGetValue( string SUID ); // return null if not found
    }
Run Code Online (Sandbox Code Playgroud)

但我试图了解我的原始代码是否真的违反了协方差,或者这是协方差的编译器还是.NET限制.

Bro*_*ass 13

问题确实在这里:

bool TryGetValue( string SUID, out T obj ); // Error here?
Run Code Online (Sandbox Code Playgroud)

您将obj标记为out参数,这仍然意味着您传入的内容 obj因此无法协变,因为您既传递了类型的实例又T返回了它.

编辑:

Eric Lippert说它比任何人都更好地提到他的答案"在C#中引用参数并且不能被标记为变体"并引用他关于out参数:

将T标记为"out"是否合法?很不幸的是,不行."out"实际上与幕后的"ref"没有什么不同."out"和"ref"之间的唯一区别是编译器禁止在被调用者分配之前从out参数读取,并且编译器在被调用者正常返回之前需要赋值.以C#以外的.NET语言编写此接口实现的人可以在初始化之前从该项读取,因此可以将其用作输入.因此,在这种情况下,我们禁止将T标记为"out".这是令人遗憾的,但我们无能为力; 我们必须遵守CLR的类型安全规则.