Is there a difference between the following two pieces of code?
class Test { public readonly double Val; public Test(bool src) { this.Val = src ? 1 : 0; } } class Test { public readonly double Val; public Test(bool src) { this.Val = src ? 1D : 0D; } }
I found that our code base uses the second way of writing.
这里有两个问题,需要注意的是,他们有不同的答案。
有没有之间的差异
double val = 1;
和double val = 1D;
?
否。C#编译器可以识别在期望使用double的上下文中何时使用整数文字,并且在编译时进行类型更改,因此这两个片段将生成相同的代码。
以下两段代码之间有区别吗?
double Val; ... this.Val = src ? 1 : 0; --- this.Val = src ? 1D : 0D;
是。将整数常量自动更改为double的规则仅适用于常量,而src ? ...
不是常量。就像您编写的那样,编译器将生成前者:
int t; if (src) t = 1; else t = 0; this.Val = (double)t;
和第二个
double t; if (src) t = 1D; else t = 0D; this.Val = t;
也就是说,在第一个中,我们选择一个整数,然后将其转换为双精度,在第二个中,我们选择一个双精度。
仅供参考:允许 C#编译器或抖动识别出可以将第一个程序优化为第二个程序,但是我不知道它是否确实可以这样做。C#编译器有时确实将用于提升算术的转换移到条件主体中。我大约在八年前就编写了该代码,但是我不记得所有的细节。
有是在生成的IL代码的差。
这节课:
class Test1 { public readonly double Val; public Test1(bool src) { this.Val = src ? 1 : 0; } }
为构造函数生成以下IL代码:
.class private auto ansi beforefieldinit Demo.Test1 extends [mscorlib]System.Object { .field public initonly float64 Val .method public hidebysig specialname rtspecialname instance void .ctor ( bool src ) cil managed { IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ldarg.0 IL_0007: ldarg.1 IL_0008: brtrue.s IL_000d IL_000a: ldc.i4.0 IL_000b: br.s IL_000e IL_000d: ldc.i4.1 IL_000e: conv.r8 IL_000f: stfld float64 Demo.Test1::Val IL_0014: ret } }
和这个类:
class Test2 { public readonly double Val; public Test2(bool src) { this.Val = src ? 1d : 0d; } }
为构造函数生成以下IL代码:
.class private auto ansi beforefieldinit Demo.Test2 extends [mscorlib]System.Object { .field public initonly float64 Val .method public hidebysig specialname rtspecialname instance void .ctor ( bool src ) cil managed { IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ldarg.0 IL_0007: ldarg.1 IL_0008: brtrue.s IL_0015 IL_000a: ldc.r8 0.0 IL_0013: br.s IL_001e IL_0015: ldc.r8 1 IL_001e: stfld float64 Demo.Test2::Val IL_0023: ret } }
如您所见,在第一个版本中,它必须调用conv.r8
才能将int转换为double。
但是:(1)最终结果是相同的,并且(2)JIT编译器可以将它们都转换为相同的机器代码。
因此,答案是:是的,有是一个区别-但不是一个,你需要操心。
就个人而言,我会选择第二个版本,因为它可以更好地表达程序员的意图,并且可能会产生效率更高的代码(取决于JIT编译器的工作方式)。