为什么不将违反方案委托给价值类型?
此代码段未在LINQPad中编译。
void Main() { (new[]{0,1,2,3}).Where(IsNull).Dump(); } static bool IsNull(object arg) { return arg == null; }
编译器的错误消息是:
‘UserQuery.IsNull(object)’没有重载匹配委托’System.Func’
它适用于字符串数组,但不适用于int[]
。 这显然与拳击有关,但我想知道细节。
给出的答案(没有涉及值类型的差异)是正确的。 当其中一个变化类型参数是值类型时,协方差和逆变不起作用的原因如下。 假设它确实起作用,并显示事情是如何发生可怕的错误:
Func f1 = ()=>123; Func
好的,会发生什么? f2与f1的引用相同。 因此无论f1做什么,f2都可以。 f1做什么? 它在堆栈上放置一个32位整数。 作业有什么作用? 它接受堆栈中的任何内容并将其存储在变量“ob”中。
拳击教学在哪里? 没有人! 我们只是将32位整数存储到期望不是整数的存储中,而是存储到包含盒装整数的堆位置的64位指针。 因此,您只是错误地对齐堆栈并使用无效引用损坏变量的内容。 很快这个过程就会火上浇油。
那么拳击教学应该去哪里? 编译器必须在某处生成装箱指令。 它不能在调用f2之后,因为编译器认为f2返回已经装箱的对象。 它不能进入f1的调用,因为f1返回一个int,而不是一个盒装的int。 它不能在f2的调用和f1的调用之间进行, 因为它们是同一个委托; 没有’之间’ 。
我们在这里唯一能做的就是让第二行真正意味着:
Func
现在我们不再在f1和f2之间有参考标识,那么方差点是什么? 协变参考转换的重点是保留参考标识 。
无论你如何切片,事情都会出现严重错误,无法解决问题。 因此,最好的办法是首先使该function非法; generics委托类型不允许存在差异,其中值类型将是变化的东西。
更新:我应该在我的回答中注意到,在VB中,您可以将一个返回int的委托转换为一个返回对象的委托。 VB只生成第二个委托,它将调用包装到第一个委托并将结果装箱。 VB选择放弃引用转换保留对象标识的限制。
这说明了C#和VB的设计理念的一个有趣的区别。 在C#中,设计团队一直在思考“编译器如何找到可能是用户程序中的错误并引起他们注意?” VB团队正在思考“我们怎样才能弄清楚用户可能意味着什么,并代表他们这样做?” 简而言之,C#哲学是“如果你看到某些东西,说些什么”,那么VB哲学就是“做我的意思,而不是我所说的”。 两者都是完全合理的哲学; 有趣的是,由于设计原则,两种具有几乎相同特征集的语言在这些小细节中是如何不同的。
因为Int32
是值类型而反对方差不适用于值类型。
你可以尝试这个:
(new **object**[]{0,1,2,3}).Where(IsNull).Dump();
它不适用于int,因为没有对象。
尝试:
上述就是C#学习教程:为什么不将违反方案委托给价值类型?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
void Fun() { IEnumerable
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1019188.html