开发者

else or return?

Which one out of following two is best wrt to performance and standard practice. How does .NET internally handles these two code snippets?

Code1

If(result)
{
  process1(开发者_运维技巧);
}
else
{
  process2();
}

Or Code 2

If(result)
{
   process1();
   return;
}
process2();


Personally I always like to return ASAP so I would go for something like:

if (result)
{
    // do something
    return;
}

// do something if not result

With regards to performance, I doubt either have any advantages over eachother it really comes down to readability and personal taste. I assume .NET would optimize your first code block to something like the above.


The performance difference, if any, is negligible in any normal case.

One standard practice (among others) is to try to keep a single exit point from a method, so that talks in favour of the first alternative.

The actual implementation for the return in the middle is most likely to make a jump to the end of the method, where the code to wrap up the stack frame for the method is, so it's likely that the final executable code is identical for the two codes.


I think the 'single exit point' is overrated. Sticking to it too dogmatically can lead to some very complex code, which should really either have multiple exit points, or be split into smaller methods.

I would say the choice between the two depends on the semantics.

'If some condition is true then do this, otherwise do that' maps perfectly onto if-else.

if (isLoggedIn) {
    RedirectToContent();
} else {
    RedirectToLogin();
}

'If some condition then do some cleanup and bail out' maps better onto Code 2. This is called the guard pattern. This leaves the body of the code as normal, clear and uncluttered by unnecessary indentation as possible. It's commonly used to validate parameters or state (check if something is null, or something is cached, things like that).

if (user == null) {
    RedirectToLogin();
    return;
}

DisplayHelloMessage(user.Name);

It's not uncommon to see both forms used in the same project. Which to use, like I say, depends on what you're trying to convey.


If there is common code, that needs to be executed after the if/else block, then option 1.

If the if-else block is the last thing to do in a function, then option 2.

Personally I always use option 1. If there is a return stateent, it comes after the else block


If you remove the braces around the 2nd version's remaining code, that's exactly what I use. I prefer to make the early validation part of a function obvious, and then I can get down to business.

That being said, it's a matter of opinion. As long as you're consistent about it, pick one and stick with it.

edit: About the performance, the emitted IL is exactly the same. Choose one or the other for the style, there is no penalty to either.


They will both compile into the same IL for Release mode (there may be a few different Nop operands in Debug..) And as such will have no performance difference. This is totally up to how you and your team feel the code is easier to read.

I used to be in the camp against early exit, but now I feel it can make code much simpler to follow.

// C#
public static void @elseif(bool isTrue)
{
    if (isTrue)
        Process1();
    else
        Process2();
}
// IL
.method public hidebysig static void  elseif(bool isTrue) cil managed
{
  // Code size       15 (0xf)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  brfalse.s  IL_0009
  IL_0003:  call       void elseif.Program::Process1()
  IL_0008:  ret
  IL_0009:  call       void elseif.Program::Process2()
  IL_000e:  ret
} // end of method Program::elseif


// C#
public static void @earlyReturn(bool isTrue)
{
    if (isTrue)
    {
        Process1();
        return;
    }
    Process2();
}
// IL
.method public hidebysig static void  earlyReturn(bool isTrue) cil managed
{
  // Code size       15 (0xf)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  brfalse.s  IL_0009
  IL_0003:  call       void elseif.Program::Process1()
  IL_0008:  ret
  IL_0009:  call       void elseif.Program::Process2()
  IL_000e:  ret
} // end of method Program::earlyReturn


Can't say about performance, but Code 1 looks a lot clearer and more logical to me. Jumping out of a function in the middle of an if block appears quite confusing and is easy to overlook.


Here's some additional reading on the guard clause: http://www.c2.com/cgi/wiki?GuardClause

One term I did not see mentioned that I think is important -- the purpose of the guard clause is to increase readability. Single exit methods can tend toward "arrow" code (where nesting of statements makes an arrowhead).


The return will cause the code to return from whatever method the if statement is in, no further code will be executed. The statement without the return will simply drop out of the if statement.


I would use Code 1, because if I add something later after the if statement, I'm still positive it will execute, without me needing to remember to remove the return clause from where it is in Code 2.


Both styles are commonplace, and religious wars have been fought over them. :-)

I normally do this:

  • If the test is expressing method contract semantics, e.g. checking input parameters for validity, then choose option 2.
  • Otherwise, choose option 1.

However, arguably a more important rule is "which is more readable and/or maintainable for the next developer who looks at the code?".

The performance difference is negligible, as others have said.


I think you should't worry about performance here. In this case readability and maintainability are way more important.

Sticking to one exit point for a routine is a good practice.

However, sometimes multiple returns just make the code a lot clearer, especially when you have a number of tests near the beginning of the code (ie checking if all of the input parameters are in the correct format) for which an 'if-true' should lead to a return.

ie:

if (date not set) return false;
age = calculateAgeBasedOnDate();
if (age higher than 100) return false;
...lots of code...
return result;


I think it does not matter. You should go for readability and I think the less brackets the better. So I would return without the last 2 brackets (see sample below). Please do not think about performance when writing something like this it won't give you anything but too much complexity at an too early stage.

if(result)
{
  process 1
  return;
}

process 2


I think the second option is better for cases of many condition (such as validation). If you use the first in these cases you will get ugly indentation.

 if (con){
    ...
    return;
 }
 if (other con){
    ...
    return;
 }
 ...
 return;


I tend to have a single point of exit, which is very useful when implementing locks in a multi-threaded environment, to make sure that the locks are released. With the first implementation, it's harder to do.


I tend to have multiple points of exit from a function. Personally I think it's clearer and in some cases it can be faster. If you check on something and then return the program won't execute any left commands. Then again as HZC said if you work on multi-threaded applications then your best shot might be using your first example. Anyway for small pieces of code it won't make any difference(probably not even for some larger ones). Most important is that you write how you feel comfortable with.


If I had to say, I would say the better practice is the if-else rather than the "implied" else. The reason being is that if someone else modifies your code, they can easily catch it by glancing over.

I recall that there is a large debate in the programming world on whether or not you should have multiple return statements in your code. One could say that it's a source of great confusion because if you have multiple loops within the "if" statement, and have conditional returns, then it could cause some confusion.

My usual practice is to have an if-else statement and a single return statement.

For example,

type returnValue;
if(true)
{
 returnValue = item;
}
else
 returnValue = somethingElse;

return returnValue;

In my opinion the above is slightly more readable. However that isn't always the case. Sometimes it's better to have a return statement in the middle of the if statement especially if it requires a tricky return statement.


It depends on what "result", "process1" and "process2" are.

If process2 is the logical consequence of "result" being false; you should go for Code 1. This is the most readable pattern if process1 and process2 are equivalent alternatives.

if (do_A_or_B = A)
  A()
else
  B()

If result is some "no-go" condition and "process1" is merely a cleanup needed on such condition you should choose Code 2. It is the most readable pattern if "process2" is the main action of the function.

if (NOT can_do_B)
{
  A() 
  return
}

B()


It depends on the context.

If this is in a function that at calculating a value, return that value as soon as you have it (option 2). You are showing you have done all the work you need to, and are leaving.

If this is code that is part of program logic then it's best to be as precise as possible (option 1). Someone looking at option 1 will know you mean (do this OR that), where as option 2 could be a mistake (in this condition do this THEN ALWAYS do that - I'll just correct it for you!). Had that before.

When compiled these will be usually the same, but we are not interested in performance. This is about readability and maintainable.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜