是什么理由这个可空< T>隐式转换操作符的行为 [英] What is the justification for this Nullable<T> behavior with implicit conversion operators

查看:194
本文介绍了是什么理由这个可空< T>隐式转换操作符的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到可空和隐式转换之间的相互作用一些有趣的行为。我发现,提供一个隐式转换为从值类型引用类型它允许可空键入要传递给需要引用类型的函数时,我反而期待一个编译错误。下面code说明了这一点:

I encountered some interesting behavior in the interaction between Nullable and implicit conversions. I found that providing an implicit conversion for a reference type from a value type it permits the Nullable type to be passed to a function requiring the reference type when I instead expect a compilation error. The below code demonstrates this:

static void Main(string[] args)
{
    PrintCatAge(new Cat(13));
    PrintCatAge(12);
    int? cat = null;
    PrintCatAge(cat);
}

private static void PrintCatAge(Cat cat)
{
    if (cat == null)
        System.Console.WriteLine("What cat?");
    else
        System.Console.WriteLine("The cat's age is {0} years", cat.Age);
}

class Cat
{
    public int Age { get; set; }
    public Cat(int age)
    {
        Age = age;
    }

    public static implicit operator Cat(int i)
    {
        System.Console.WriteLine("Implicit conversion from " + i);
        return new Cat(i);
    }
}

输出:

The cat's age is 13 years
Implicit conversion from 12
The cat's age is 12 years
What cat?

如果在转换code从然后删除您获得预期的错误:

If the conversion code is removed from Cat then you get the expected errors:

错误3的最佳重载方法匹配'ConsoleApplication2.Program.PrintCatAge(ConsoleApplication2.Program.Cat)'有一些无效参数

Error 3 The best overloaded method match for 'ConsoleApplication2.Program.PrintCatAge(ConsoleApplication2.Program.Cat)' has some invalid arguments

错误4参数1:不能从转换'诠释?以ConsoleApplication2.Program.Cat

Error 4 Argument 1: cannot convert from 'int?' to 'ConsoleApplication2.Program.Cat

如果您ILSpy打开可执行文件生成的code如下:

If you open the executable with ILSpy the code that was generated is as follows

int? num = null;
Program.PrintCatAge(num.HasValue ? num.GetValueOrDefault() : null);

在一个类似实验中我删除了转换,并增加了超载 PrintCatAge 接受一个int(不能为空),看看如果编译器将执行一个类似的操作,但它不

In a similar experiment I removed the conversion and added an overload to PrintCatAge that takes an int (not nullable) to see if the compiler would perform a similar operation, but it does not.

我明白发生了什么,但我不明白的理由吧。此行为是意外,我和似乎很奇怪。我没有任何成功找到文档中的转换任何提及这一行为MSDN上或可空< T>

I understand what is happening, but I don't understand the justification for it. This behavior is unexpected to me and seems odd. I did not have any success finding any reference to this behavior on MSDN in the documentation for conversions or Nullable<T>.

我提出再是问题,这是有意的,是有一个解释,为什么会这样?

The question I pose then is, is this intentional and is there a explanation why this is happening?

推荐答案

我此前曾表示,(1)这是一个编译器错误和(2)它是一个新的。第一个说法是准确的;第二次是我感到困惑,我曾急促去上车时间。 (我在想那的bug是新的我是一个更复杂的bug,涉及解禁的转换和提升增值运营商。)

I said earlier that (1) this is a compiler bug and (2) it is a new one. The first statement was accurate; the second was me getting confused in my haste to get to the bus on time. (The bug I was thinking of that is new to me is a much more complicated bug involving lifted conversions and lifted increment operators.)

这是长期存在的一个已知的编译器错误。乔恩斯基特首先把它带到了我的注意,前一段时间,我相信有一个计算器问题,关于它的地方;我不记得在哪里随便。也许乔恩一样。

This is a known compiler bug of long standing. Jon Skeet first brought it to my attention some time ago and I believe there's a StackOverflow question about it somewhere; I do not recall where offhand. Perhaps Jon does.

那么,这个bug。让我们定义一个解禁操作符。如果操作员从非空值S型转换到非可空值类型T,然后也有一个取消操作符,它把来自S'到T 2,使得空S'变换为一个空T'和一个非空S'转换到T?通过展开S'以S,将S到T,和包装T可T'。

So, the bug. Let's define a "lifted" operator. If an operator converts from a non-nullable value type S to a non-nullable value type T then there is also a "lifted" operator that converts from S? to T?, such that a null S? converts to a null T? and a non-null S? converts to T? by unwrapping S? to S, converting S to T, and wrapping T to T?.

该规范指出,(1)的只有的情况,其中有一个提升运算符是当S和T都是非空值类型,和(2)的解禁和非提升转换运算符的两个的视为对它们是否为转换适用候选人和如果同时适用,则所适用的转换,提升或unlifted的源和目标类型,被用来确定最佳源类型,最好的目标类型,最终,所有适用的转换最好的转换。

The specification says that (1) the only situation in which there is a lifted operator is when S and T are both non-nullable value types, and (2) that the lifted and non-lifted conversion operators are both considered as to whether they are applicable candidates for the conversion and if both applicable, then the source and target types of the applicable conversions, lifted or unlifted, are used to determine the best source type, best target type, and ultimately, best conversion of all the applicable conversions.

不幸的是,实行彻底违反了所有这些规则,而这样做,因为我们无法改变不会破坏现有的许多节目的方式。

Unfortunately, the implementation thoroughly violates all of these rules, and does so in a way that we cannot change without breaking many existing programs.

首先,我们违反了有关解除运营商的生存规则。一个提升运算符被认为是实施存在,如果S和T都是非空值类型,或者如果S是一个非空的值类型和T是任意类型到一个空的可分配:引用类型,可为空值型,或指针类型。在所有这些情况下,我们生产出提升运算符。

First off, we violate the rule about the existence of lifted operators. A lifted operator is considered by the implementation to exist if S and T are both non-nullable value types, or if S is a non-nullable value type and T is any type to which a null could be assigned: reference type, nullable value type, or pointer type. In all those cases we produce a lifted operator.

在您的特定情况下,我们提升到为空的话,我们将一个可空类型的引用类型猫通过检查空。如果源不为空,然后我们通常转换;如果是这样,那么我们生产一个空猫。

In your particular case, we lift to nullable by saying that we convert a nullable type to the reference type Cat by checking for null. If the source is not null then we convert normally; if it is, then we produce a null Cat.

其次,违反彻底有关如何确定适用的候选人的最佳来源和目标类型时,这些候选人之一,是提升运营商的规则,我们也违反了有关确定这是最好的运营商的规则。

Second, we violate thoroughly the rule about how to determine the best source and target types of applicable candidates when one of those candidates is a lifted operator, and we also violate the rules about determining which is the best operator.

总之,这是一个不能被固定而不会破坏真正的客户弄得一塌糊涂,所以我们可能会铭记在罗斯林的行为。我会考虑在某一时刻记录在我的博客编译器的具体行为,但我不会认为我的呼吸,等待这一天的到来,如果我是你。

In short, it is a big mess that cannot be fixed without breaking real customers, and so we will likely enshrine the behaviour in Roslyn. I will consider documenting the exact behaviour of the compiler in my blog at some point, but I would not hold my breath while waiting for that day if I were you.

当然,很多道歉的错误。

And of course, many apologies for the errors.

这篇关于是什么理由这个可空&LT; T&GT;隐式转换操作符的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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