Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
355 views
in Technique[技术] by (71.8m points)

c# - In equal comparison of a literal value does the order of operands matter?

I am accustomed to write the code as(just an example)

Request.QueryString["xxxx"] != null

Recently someone said that

null != Request.QueryString["xxxx"]

gives a better performance.

I am curious to know as whether it actually brings any difference or not and if so how?

Note~ The above is just an example. To be generically speaking

Whether

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

is better than

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

Thanks

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

What

It's a coding style in use for languages with many implicit type conversions (friendly named Yoda from Star Wars character because of his OSV word order). Sometimes it's even enforced and required by project guide-lines to prevent some kind of errors derived from typos. Different languages have different variations and extensions of this style but I'll limit this answer to C and C#.

Why Yes

For example in C you can write:

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

This code will assign to a the value returned from CalculateValue() then it'll overwrite the value with the result of CalculateAnotherValue() and if it's not zero then it'll execute the code. Probably it's not what intended to do and the assignment in the if expression is a mistake. From your example with NULL then you may have:

if (pBuffer = NULL)

Again probably it's not what you want (and it's a quite common mistake), you'll assign NULL to the pointer and the condition will be always false. If you write:

if (NULL = pBuffer)

It won't compile (because you can't assign a value to a literal) and you'll get a compile-time error.

This kind of compile time checks are not the only reason to use this coding style, look this C# (very common) code:

if (text != null && text.Equals("something", StringComparison.InvariantCulture)
    DoSomething();

It could be contracted to:

if ("something".Equals(text, StringComparison.InvariantCulture))
    DoSomething();

Why No

In C# usually it doesn't matter. It's a practice inherited from C/C++. Because in C# expressions are not converted automatically to bool then following code won't compile:

if (Request.QueryString["PartnerID"] = null)

Then this practice is useless in C# (with the exception pointed out by @IlianPinzon in the comments), nothing about performance it was used only to avoid such kind of mistakes.

About the last example in the Why yes section the problem is readability, to write "something".Equals(text) is like to say "if happy is the guy" instead of "if the guy is happy".

Performance

Starting from these functions:

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

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

They produce following 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 

The only difference is in lines L_0001 and L_0002, they're just swapped but order of its operands doesn't change the behavior of ceq. Even if you override Equals() method the JIT compiler will produce the same assembly code for both expressions (because the comparison will be always done by Equals(), null is typeless).

Things can be more complicated if the comparison involves a user defined equality comparer, in this case there is not a rule and it'll depend on the effective op_Equals implementation. For example this == implementation:

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);
}

In this case if the first operand is null the execution will be slightly faster (because MyType.Equals() won't be even called) but this performance gain is very small: you save one comparison, few jumps and a virtual function call. Moreover you can rewrite the function to be faster in the opposite case (in case you really matter about this).

Here a small test where MyType.Equals(object) simply returns true for any non null parameter. The test will be looped Int32.MaxValue times:

Operation       Total time (ms)
lhs == null               10521
null == lhs                2346

It seems the "optimized" version that avoid unnecessary call to Equals() is five times faster but note that the loop count is very high and actual implementation of Equals() is empty, a true implementation will reduce the relative overhead of the function call (and probably you'll have something else than this micro-optimization to do). For system classes you can't rely on this details, for example String.Equals() will be always called by operators (no matters the order) but you can't assume one code path is faster and this fact won't change in future versions of the framework (or for different CPU architectures).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...