不明白使用Nullabletypes的pre decrement操作符行为

好吧,对于你们中的一些人来说,这可能是显而易见的,但是我对于从这个相当简单的代码中得到的行为难以理解:

public static void Main(string[] args) { int? n = 1; int i = 1; n = ++n - --i; Console.WriteLine("Without Nullable<int> n = {0}", n); //outputs n = 2 n = 1; i = 1; n = ++n - new Nullable<int>(--i); Console.WriteLine("With Nullable<int> n = {0}", n); //outputs n = 3 Console.ReadKey(); } 

我预计两个输出是相同的,等于2但奇怪的是,他们没有。 有人能解释为什么吗?

编辑:虽然代码产生这种“怪异”的行为是公认的做作,它看起来像一个错误在C#编译器,虽然看起来不重要,原因似乎是内联new如詹姆斯最初指出的。 但行为不限于操作。 方法调用的行为方式完全相同,也就是说,它们在被调用一次时被调用两次。

考虑下面的repro:

 public static void Main() { int? n = 1; int i = 1; n = n - new Nullable<int>(sideEffect(ref i)); Console.WriteLine("With Nullable<int> n = {0}", n); Console.ReadKey(); } private static int sideEffect(ref int i) { Console.WriteLine("sideEffect({0}) called", i); return --i; } 

果然,输出为2时应该是1并且"sideEffect(i) called"被打印出两次。

编辑:这已被确认为团队在编译器中的错误。 它在Roslyn修复。 作为一个解决方法,使用cast (int?)(--i)来阻止错误出现,或者不首先将其显式转换为Nullable<int>

第一个代码块在reflection器中生成以下代码:

 int? nullable3; int? nullable = 1; int num = 1; int? nullable2 = nullable; nullable2 = nullable = nullable2.HasValue ? new int?(nullable2.GetValueOrDefault() + 1) : ((int?) (nullable3 = null)); int num2 = --num; nullable = nullable2.HasValue ? new int?(nullable2.GetValueOrDefault() - num2) : ((int?) (nullable3 = null)); Console.WriteLine("Without Nullable<int> n = {0}", nullable); 

第二个如下:

 nullable = 1; num = 1; nullable2 = nullable; nullable2 = nullable = nullable2.HasValue ? new int?(nullable2.GetValueOrDefault() + 1) : ((int?) (nullable3 = null)); num2 = --num; nullable = nullable2.HasValue ? new int?(nullable2.GetValueOrDefault() - --num) : null; Console.WriteLine("With Nullable<int> n = {0}", nullable); 

它们或多或less是相同的,直到可以为nullable 。 它运行两次,导致它运行2 - -1 ,导致3。

它也像i = ~i这样的expression式,但不是与方法调用expression式…

这是一个非常有趣的问题,从我看到编译器似乎不止一次地评估-- / ++语句。 例如,以下内容:

 n = ++n - new Nullable<int>(i++) 

导致n变成0 (你会期望的),但是i现在是3 (你期望是2 )。 但是,如果我这样做

 n = ++n - new Nullable<int>(i); 

然后我得到预期的结果( n = 1i = 1

我只能假设这与某些 new Nullable调用是联系new Nullable 。 我不认为这是一个很大的问题,因为这可能不被认为是你的日常代码,但是,在我看来,它似乎是编译器的一个错误。

那么最奇怪的是,我试图追查“ – ”的实际代码,但是我不能,但如果你这样做的话

  n = 1; i = 1; n = ++n - new Nullable<int>(i--); Console.WriteLine("With Nullable<int> n = {0}", n); //outputs n = 2 Console.ReadKey(); 

它按预期输出。

编辑:全部显示:

http://msdn.microsoft.com/en-US/library/wc3z3k8c(v=vs.80).aspx

这是因为在这条线上:

  n = ++n - new Nullable<int>(--i); 

我变成-1和2 – (-1)= 3;

它变成负数1的原因是你正在创build一个初始化为0的无效对象,然后减去一个(i)。

您可以在您的浏览器中将此代码作为* .cshtml文件运行:

 @{ int? m = 1; int i = 1; m = ++m - --i; //MessageBox.Show("Without Nullable<int> n = {0}", n); //outputs n = 2 int? n = 1; i = 1; n = ++n - new Nullable<int>(--i); //MessageBox.Show("With Nullable<int> n = {0}", n); //outputs n = 3 } <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title></title> </head> <body> <h2>m = @m</h2> <h2>n = @n</h2> </body> </html>