为什么C#out泛型类型参数违反协方差? [英] Why do C# out generic type parameters violate covariance?

查看:56
本文介绍了为什么C#out泛型类型参数违反协方差?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不清楚为什么以下代码段不是协变的?

I'm unclear as to why the following code snippet isn't 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?
    }

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

Error 1 Invalid variance: The type parameter 'T' must be invariantly valid on 'IResourceColl.TryGetValue(string, out T)'. 'T' is covariant.

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

My interface only uses the template parameter in output positions. I could easily refactor this code to something like

  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
    }

但是我想了解我的原始代码是否确实违反了协方差,或者这是编译器或.NET协方差的限制.

but I'm trying to understand if my original code actually violates covariance or if this is a compiler or .NET limitation of covariance.

推荐答案

问题确实在这里:

bool TryGetValue( string SUID, out T obj ); // Error here?

您将obj标记为 out 参数,这仍然意味着,尽管您正在传入 obj ,所以它不能是协变的,因为你们俩传入 T 类型的实例并返回它.

You marked obj as out parameter, that still means though that you are passing in obj so it cannot be covariant, since you both pass in an instance of type T as well as return it.

埃里克·利珀特(Eric Lippert)说的要比我提到的任何人都要好.他对"C#中的引用和退出参数,不能标记为变体"的回答并引用他的 out 参数:

Eric Lippert says it better than anyone I refer to his answer to "ref and out parameters in C# and cannot be marked as variant" and quote him in regards to out parameters:

将T标记为"out"是否合法?抱歉不行.出去"实际上与幕后的引用"没什么不同.唯一的"out"和"ref"之间的区别是编译器禁止在被调用方分配之前从out参数中读取,并且编译器需要在被调用者返回之前进行赋值一般.有人在除了C#之外的.NET语言也可以从该项目中读取它已初始化,因此可以用作输入.我们因此禁止在这种情况下将T标记为出" .真遗憾但是我们对此无能为力;我们必须遵守类型安全规则CLR.

Should it be legal to make T marked as "out"? Unfortunately no. "out" actually is not different than "ref" behind the scenes. The only difference between "out" and "ref" is that the compiler forbids reading from an out parameter before it is assigned by the callee, and that the compiler requires assignment before the callee returns normally. Someone who wrote an implementation of this interface in a .NET language other than C# would be able to read from the item before it was initialized, and therefore it could be used as an input. We therefore forbid marking T as "out" in this case. That's regrettable, but nothing we can do about it; we have to obey the type safety rules of the CLR.

这篇关于为什么C#out泛型类型参数违反协方差?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆