c# - 在对文字值进行相等比较时,操作数的顺序重要吗?

标签 c# .net performance

我习惯把代码写成(只是一个例子)

Request.QueryString["xxxx"] != null

最近有人说
null != Request.QueryString["xxxx"]

提供更好的性能。

我很想知道它是否真的带来了任何区别,如果有的话,如何?

注意~以上只是一个例子。笼统地说

无论
Constant [Operator] Actual Value (e.g. 1 == Convert.ToInt32(textbox1.text))


Actual Value [Operator] Constant (e.g. Convert.ToInt32(textbox1.text) == 1)

谢谢

最佳答案

什么

这是一种用于具有许多隐式类型转换的语言的编码风格(由于他的 OSV 词序,因此友好地命名为来自星球大战角色的 Yoda)。有时它甚至被项目指南强制执行和要求,以防止由于拼写错误而导致的某种错误。不同的语言对这种风格有不同的变体和扩展,但我将把这个答案限制在 C 和 C#。

为什么是

例如在 C 中你可以写:

int a = CalculateValue();
if (a = CalculateAnotherValue()) {
    /* Do something */
}

此代码将分配给 aCalculateValue() 返回的值然后它将用 CalculateAnotherValue() 的结果覆盖该值如果它不为零,那么它将执行代码。可能这不是我们打算做的,也不是 if 中的任务。表达是错误的。从你的例子 NULL那么你可能有:
if (pBuffer = NULL)

同样,这可能不是您想要的(这是一个很常见的错误),您会将 NULL 分配给指针,并且条件将始终为假。如果你写:
if (NULL = pBuffer)

它不会编译(因为您无法为文字赋值)并且您将收到编译时错误。

这种编译时检查并不是使用这种编码风格的唯一原因,看看这个 C#(很常见)代码:
if (text != null && text.Equals("something", StringComparison.InvariantCulture)
    DoSomething();

它可以签约为:
if ("something".Equals(text, StringComparison.InvariantCulture))
    DoSomething();

为什么不

在 C# 中通常没有关系。这是从 C/C++ 继承的实践。因为在 C# 中表达式不会自动转换为 bool那么以下代码将无法编译:
if (Request.QueryString["PartnerID"] = null)

那么这种做法在 C# 中是没有用的(@IlianPinzon 在评论中指出的异常(exception)),它只用于避免此类错误的性能。

关于为什么是部分中的最后一个例子,问题是可读性,写 "something".Equals(text)喜欢说“如果那个人快乐”而不是“如果那个人快乐”。

表现

从这些函数开始:
static bool TestRight(object value)
{ return value == null; }

static bool TestLeft(object value)
{ return null == value; }

他们产生以下IL:
.maxstack 2
.locals init ([0] bool CS$1$0000)
L_0000: nop 
L_0001: ldnull 
L_0002: ldarg.0 
L_0003: ceq 
L_0005: stloc.0 
L_0006: br.s L_0008
L_0008: ldloc.0 
L_0009: ret 

唯一的区别在于 L_0001 和 L_0002 行,它们只是交换了但其操作数的顺序不会改变 ceq 的行为.即使您覆盖 Equals() JIT 编译器将为两个表达式生成相同的汇编代码(因为比较总是由 Equals() 完成,null 是无类型的)。

如果比较涉及用户定义的相等比较器,事情可能会更加复杂,在这种情况下,没有规则,它将取决于有效的 op_Equals执行。例如这个 ==执行:
public static bool operator==(MyType lhs, MyType rhs)
{
    if (Object.ReferenceEquals(lhs, rhs))
        return true;

    if (Object.ReferenceEquals(lhs, null))
        return false;

    return lhs.Equals(rhs);
}

在这种情况下,如果第一个操作数是 null执行速度会稍微快一些(因为 MyType.Equals() 甚至不会被调用)但是这种性能增益非常小:您节省了一次比较、很少的跳转和一个虚函数调用。此外,您可以在相反的情况下将函数重写为更快(如果您真的对此很重要)。

这里有一个小测试MyType.Equals(object)只需返回 true对于任何非 null范围。测试将循环Int32.MaxValue次:

操作总时间(毫秒)
lhs == null 10521
null == lhs 2346

似乎是“优化”版本,可避免不必要的调用 Equals()速度快了五倍,但请注意循环计数非常高,而且 Equals() 的实际实现为空,真正的实现将减少函数调用的相对开销(并且可能除了这个 微优化 之外,您还有其他事情要做)。对于系统类,您不能依赖此详细信息,例如 String.Equals()将始终由运算符(operator)调用(无论顺序如何),但您不能假设一个代码路径更快,而且这一事实在框架的 future 版本中(或对于不同的 CPU 架构)不会改变。

关于c# - 在对文字值进行相等比较时,操作数的顺序重要吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10811410/

相关文章:

python - Pandas 迭代更新列值

java - 优化此代码以查找连接的组件?

c# - log4net:错误 XmlConfigurator:无法在应用程序的 .config 中找到配置部分 'log4net'

c# - 我如何让 NHibernate 进行连接?

c# - block Control+Alt+Delete

c# - 使用 Webclient.Uploadfile 在文件上传期间获取上传进度

c# - Visual Studio 插件显示资源文件中的文本而不是代码

c# - .net 核心应用程序错误 502.5 如果在 IIS 中作为虚拟目录运行

c# - 为什么这个 byte* 和 uint 的加法不能进位到更高的 dword 中?

java - 如何使用 Java(无 DB)更快地删除文件中的重复/聚合行