不理解Nullable类型的预减运算符行为
本文关键字:运算符 Nullable 类型 不理解 | 更新日期: 2023-09-27 18:15:59
好的,这对你们中的一些人来说可能是显而易见的,但我对我从这段相当简单的代码中得到的行为感到困惑:
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
,但奇怪的是它们不是。有人能解释一下原因吗?
EDIT:虽然生成这种"奇怪"行为的代码无可否认是人为的,但它看起来确实像c#编译器中的错误,尽管看起来不重要,原因似乎是内联new
,正如James最初指出的那样。但这种行为并不局限于操作。方法调用的行为完全相同,也就是说,当它们只应该被调用一次时,它们被调用了两次。
考虑下面的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;
}
果然应该是1
,输出却是2
, "sideEffect(i) called"
打印了两次
EDIT:这已经被团队确认为编译器中的一个bug。它被固定在罗斯林。作为一种解决方法,使用强制转换(int?)(--i)
来阻止错误的出现,或者一开始就不显式地将其强制转换为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
这样的表达式做同样的事情,但不包括方法调用表达式…
这是一个相当有趣的问题,从我可以看到编译器出现计算--
/++
语句不止一次。例如:
n = ++n - new Nullable<int>(i++)
导致n
变成0
(这是您所期望的),但i
现在是3
(这是您所期望的2
)。但是,如果我这样做
n = ++n - new Nullable<int>(i);
然后我得到预期的结果(n
= 1
和i
= 1
)
我只能假设这是在某种程度上与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();
按预期输出。
编辑:All is revealed:
http://msdn.microsoft.com/en-US/library/wc3z3k8c (v = vs.80) . aspx
这是因为在这一行:
n = ++n - new Nullable<int>(--i);
i变为-1,2 - (-1)= 3;
它变为- 1的原因是您正在创建一个可空对象,该对象初始化为0,然后减去1 (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>