41

好的,这对你们中的一些人来说可能很明显,但我对我从这个相当简单的代码中得到的行为感到困惑:

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# 编译器中的一个错误,尽管看起来并不重要,原因似乎是newJames最初指出的内联。但行为不限于操作。方法调用的行为方式完全相同,也就是说,当它们只应该被调用一次时,它们被调用了两次。

考虑以下重现:

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"被打印了两次。

4

4 回答 4

20

编辑:这已被团队确认为编译器中的错误。它固定在罗斯林。作为一种解决方法,使用强制(int?)(--i)转换来阻止错误出现,或者首先不要将其明确地强制转换为 a Nullable<int>

第一个代码块在反射器中生成以下内容:

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);

它们或多或少相同,直到分配给nullable. 它运行--num了两次,导致它运行2 - -1,导致 3。

它也对像这样的表达式做同样的事情i = ~i,但不是对方法调用表达式......

于 2013-05-29T16:34:09.887 回答
4

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

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

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

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

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

我只能假设这与在线呼叫有关new Nullable。我真的不认为这是一个很大的问题,因为这可能不会被视为您的日常代码,但是,在我看来,它似乎确实是编译器的一个错误。

于 2013-05-29T16:30:34.567 回答
-2

好吧,最奇怪的是,我试图从“--”中找出实际代码,但我无法做到,但如果你这样做了

            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

于 2013-05-29T16:36:19.170 回答
-3

这是因为在这一行:

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

i 变为 -1 和 2 - (-1) = 3;

它变为负 1 的原因是您正在新建一个初始化为 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>
于 2013-05-29T16:48:19.663 回答