C# 将长值与int/long零常量进行比较

C# 将长值与int/long零常量进行比较,c#,optimization,C#,Optimization,这是: if (myLongValue > 0) // 0 is displayed as int in Visual Studio tooltip 等于: if (myLongValue > 0L) 这是使用特殊的操作码吗?(类似于x86 asm中的JZ-jump if zero)。就IL而言,2是完全等效的。让我们以以下代码段为例: public static void Main(string[] args) { long myLongValue = long.Par

这是:

if (myLongValue > 0) // 0 is displayed as int in Visual Studio tooltip
等于:

if (myLongValue > 0L)

这是使用特殊的操作码吗?(类似于x86 asm中的JZ-jump if zero)。

就IL而言,2是完全等效的。让我们以以下代码段为例:

public static void Main(string[] args)
{
    long myLongValue = long.Parse("123");
    if (myLongValue > 0)
    {
        Console.WriteLine("ok");
    }
}
它被编译为以下IL(在发布模式下):

现在将
if(myLongValue>0)
替换为
if(myLongValue>0L)
,得到严格等效的IL

更理想的IL应该是这样,但不幸的是,我无法使编译器发出它:

.method public hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int64 myLongValue)
    L_0000: ldstr "123"
    L_0005: call int64 [mscorlib]System.Int64::Parse(string)
    L_000a: stloc.0 
    L_000b: ldloc.0 
    L_000c: ldc.i8.0 
    L_000d: ble.s L_001a
    L_0010: ldstr "ok"
    L_0015: call void [mscorlib]System.Console::WriteLine(string)
    L_001a: ret 
}

这里我们不需要
conv.i8
指令,因为我们直接将提供的Int64类型的值作为Int64推送到求值堆栈上。

在第一个示例中,运算符
的左侧是
long
System.Int64
),右侧是
int
System.Int32
)。由于C#规范没有定义带有该签名的
运算符的重载,因此我们必须检查某些转换是否适用于一个(或两个)参数(操作数)

存在从
int
long
的隐式转换。另一个方向的转换不是隐式的。因此,右侧通过加宽转换进行转换,并使用重载
运算符>(长x,长y)

因为在本例中,右边的
int
是编译时文本,编译器可以扩展常量,因此编译后两个示例之间没有差异。另一个答案演示了输出IL的外观

那么,如果你有:

ulong myULongValue = XXX;
if (myULongValue > 0)
    ...
一般来说,没有从
int
(有符号)到
ulong
(无符号)的隐式转换。但是,当
int
是一个编译时常量(literal)碰巧是非负的时,确实存在转换。因此我上面的示例仍然有效(并产生与
if(myULongValue>0ul)

但对于非常量
int
,它必须失败:

ulong myULongValue = XXX;
int zero = 0;               // not const
if (myULongValue > zero)    // will NOT compile!
    ...
ulong myULongValue = XXX;
int zero = 0;               // not const
if (myULongValue > zero)    // will NOT compile!
    ...