以下两个C#函数的区别仅在于将参数的左/右顺序交换为等于运算符==. (IsInitialized的类型是bool).使用 C#7.1 和 .NET 4.7 .
The following two C# functions differ only in swapping the left/right order of arguments to the equals operator, ==. (The type of IsInitialized is bool). Using C# 7.1 and .NET 4.7.
static void A(ISupportInitialize x) { if ((x as ISupportInitializeNotification)?.IsInitialized == true) throw null; }static void B(ISupportInitialize x) { if (true == (x as ISupportInitializeNotification)?.IsInitialized) throw null; }
但是第二个代码的 IL代码似乎要复杂得多.例如, B 是:
But the IL code for the second one seems much more complex. For example, B is:
- 长36个字节(IL代码);
- 调用其他功能,包括newobj和initobj;
- 宣布四个本地人,而只宣布一个.
- 36 bytes longer (IL code);
- calls additional functions including newobj and initobj;
- declares four locals versus just one.
函数"B"的IL ...
[0] bool flag, [1] bool flag2, [2] valuetype [mscorlib]Nullable`1<bool> nullable, [3] valuetype [mscorlib]Nullable`1<bool> nullable2 nop ldc.i4.1 stloc.1 ldarg.0 isinst [System]ISupportInitializeNotification dup brtrue.s L_0018 pop ldloca.s nullable2 initobj [mscorlib]Nullable`1<bool> ldloc.3 br.s L_0022 L_0018: callvirt instance bool [System]ISupportInitializeNotification::get_IsInitialized() newobj instance void [mscorlib]Nullable`1<bool>::.ctor(!0) L_0022: stloc.2 ldloc.1 ldloca.s nullable call instance !0 [mscorlib]Nullable`1<bool>::GetValueOrDefault() beq.s L_0030 ldc.i4.0 br.s L_0037 L_0030: ldloca.s nullable call instance bool [mscorlib]Nullable`1<bool>::get_HasValue() L_0037: stloc.0 ldloc.0 brfalse.s L_003d ldnull throw L_003d: ret
奖金.每个堆栈的最终最终JITted x86或AMD64代码如何?
BONUS. How does the respective final JITted x86 or AMD64 code for each stack up?
基于注释反馈的其他注释.首先,提出了第三个变体,但它给出与 A 相同的IL(对于Debug和Release构建).顺便说一句,新版本的 C#似乎比 A 更漂亮:
[edit] Additional notes based on feedback in the comments. First, a third variant was proposed, but it gives identical IL as A (for both Debug and Release builds). Sylistically, however, the C# for the new one does seem sleeker than A:
static void C(ISupportInitialize x) { if ((x as ISupportInitializeNotification)?.IsInitialized ?? false) throw null; }这里也是每个功能的Release IL.请注意,对于Release IL, A / C 与 B 的不对称性仍然很明显,因此原始问题仍然存在. 释放功能'A','C'的IL ...
Here also is the Release IL for each function. Note that the asymmetry A/C vs. B is still evident with the Release IL, so the original question still stands.
ldarg.0 isinst [System]ISupportInitializeNotification dup brtrue.s L_000d pop ldc.i4.0 br.s L_0012 L_000d: callvirt instance bool [System]ISupportInitializeNotification::get_IsInitialized() brfalse.s L_0016 ldnull throw L_0016: ret释放功能'B'的IL ...
[0] valuetype [mscorlib]Nullable`1<bool> nullable, [1] valuetype [mscorlib]Nullable`1<bool> nullable2 ldc.i4.1 ldarg.0 isinst [System]ISupportInitializeNotification dup brtrue.s L_0016 pop ldloca.s nullable2 initobj [mscorlib]Nullable`1<bool> ldloc.1 br.s L_0020 L_0016: callvirt instance bool [System]ISupportInitializeNotification::get_IsInitialized() newobj instance void [mscorlib]Nullable`1<bool>::.ctor(!0) L_0020: stloc.0 ldloca.s nullable call instance !0 [mscorlib]Nullable`1<bool>::GetValueOrDefault() beq.s L_002d ldc.i4.0 br.s L_0034 L_002d: ldloca.s nullable call instance bool [mscorlib]Nullable`1<bool>::get_HasValue() L_0034: brfalse.s L_0038 ldnull throw L_0038: ret最后,提到了使用新的 C#7 语法的版本,该版本似乎产生了最干净的IL:
Lastly, a version using new C# 7 syntax was mentioned which seems to produce the cleanest IL of all:
static void D(ISupportInitialize x) { if (x is ISupportInitializeNotification y && y.IsInitialized) throw null; }释放功能'D'的IL ...
[0] class [System]ISupportInitializeNotification y ldarg.0 isinst [System]ISupportInitializeNotification dup stloc.0 brfalse.s L_0014 ldloc.0 callvirt instance bool [System]ISupportInitializeNotification::get_IsInitialized() brfalse.s L_0014 ldnull throw L_0014: ret推荐答案
所以我很好奇答案,并研究了c#6规范(不知道c#7规范的托管位置).完全免责声明:我不保证我的回答是正确的,因为我没有编写c#规范/编译器,并且我对内部结构的理解受到限制.
So I was curious about the answer and took a look at the c# 6 specification (no clue where the c# 7 spec is hosted). Full disclaimer: I do not guarantee that my answer is correct, because I did not write the c# spec/compiler and my understanding of the internals is limited.
但我认为答案在于可重载 ==运算符. ==的最佳适用重载是通过使用更好的功能成员.
Yet I think that the answer lies in the resultion of the overloadable == operator. The best applicable overload for == is determined by using the rules for better function members.
根据规格:
给出一个带有一组参数表达式{E1,E2, ...,En}和两个适用的带有参数的函数成员Mp和Mq 类型{P1,P2,...,Pn}和{Q1,Q2,...,Qn},Mp定义为 比Mq更好的功能成员
Given an argument list A with a set of argument expressions {E1, E2, ..., En} and two applicable function members Mp and Mq with parameter types {P1, P2, ..., Pn} and {Q1, Q2, ..., Qn}, Mp is defined to be a better function member than Mq if
对于每个参数,从Ex到Qx的隐式转换并不更好 比从Ex到Px的隐式转换,并且至少要转换一个 参数,从Ex到Px的转换要好于转换 从Ex到Qx.
for each argument, the implicit conversion from Ex to Qx is not better than the implicit conversion from Ex to Px, and for at least one argument, the conversion from Ex to Px is better than the conversion from Ex to Qx.
引起我注意的是参数列表{E1, E2, .., En}.如果将Nullable<bool>与bool进行比较,则参数列表应该类似于{Nullable<bool> a, bool b},对于该参数列表,Nullable<bool>.Equals(object o)方法似乎是最好的功能,因为它只需要从bool进行一次隐式转换.到object.
What caught my eye is the argument list {E1, E2, .., En}. If you compare a Nullable<bool> to a bool the argument list should be something like {Nullable<bool> a, bool b}and for that argument list the Nullable<bool>.Equals(object o) method seems to be the best function, because it only takes one implicit conversion from bool to object.
但是,如果将参数列表的顺序恢复为{bool a, Nullable<bool> b},则Nullable<bool>.Equals(object o)方法不再是最好的功能,因为现在您必须在第一个参数中将Nullable<bool>转换为bool在第二个参数中从bool到object.这就是为什么对于情况 A 选择了不同的重载,这似乎会导致更清晰的IL代码.
However if you revert the order of the argument list to {bool a, Nullable<bool> b} the Nullable<bool>.Equals(object o) method no longer is the best function, because now you would have to convert from Nullable<bool> to bool in the first argument and then from bool to object in the second argument. That's why for case A a different overload is selected which seems to result in cleaner IL code.
再次说明,这是我对好奇心的满足,并且似乎符合c#规范.但是我还没有弄清楚如何调试编译器以了解实际情况.
Again this is an explanation that satisfies my own curiosity and seems to be in line with the c# spec. But I have yet to figure out how to debug the compiler to see what's actually going on.
更多推荐
带有Nullable< T>的'=='的参数顺序
发布评论