tabs ↹ over ␣ ␣ ␣ spaces

by Jiří {x2} Činčura

Try catch return bool

24 Jan 2012 .NET, C#

I was recently writing a lot of method that talked to 3rd party API. And after small refactoring a lot of methods was like try to call some method, if it throws exception return false, if not return true. And I was wondering, what’s the best (in terms of code being generated, speed, efficiency but also readability) way to write it.

I found basically three ways to write it (sure there are other ways):

try
{
	FooBar();
	return true;
}
catch (SomeException ex)
{
	LogException(ex);
	return false;
}
try
{
	FooBar();
	return true;
}
catch (SomeException ex)
{
	LogException(ex);
}
return false;
bool result = false;
try
{
	FooBar();
	result = true;
}
catch (SomeException ex)
{
	LogException(ex);
}
return result;

No magic. The third way is probably something you might recognize, if you were programming couple of years in Delphi/(Object)Pascal. Anyway, back to basics. My friend ildasm is going to help us with initial review, what we have actually done.

Everything compiled with full optimization turned on.

.method private hidebysig static bool  Test1() cil managed
{
  // Code size       28 (0x1c)
  .maxstack  1
  .locals init (class TryCatchTest.SomeException V_0,
           bool V_1)
  IL_0000:  nop
  .try
  {
    IL_0001:  nop
    IL_0002:  call       void TryCatchTest.Program::FooBar()
    IL_0007:  nop
    IL_0008:  ldc.i4.1
    IL_0009:  stloc.1
    IL_000a:  leave.s    IL_0019
  }  // end .try
  catch TryCatchTest.SomeException
  {
    IL_000c:  stloc.0
    IL_000d:  nop
    IL_000e:  ldloc.0
    IL_000f:  call       void TryCatchTest.Program::LogException(class [mscorlib]System.Exception)
    IL_0014:  nop
    IL_0015:  ldc.i4.0
    IL_0016:  stloc.1
    IL_0017:  leave.s    IL_0019
  }  // end handler
  IL_0019:  nop
  IL_001a:  ldloc.1
  IL_001b:  ret
} // end of method Program::Test1
.method private hidebysig static bool  Test2() cil managed
{
  // Code size       32 (0x20)
  .maxstack  1
  .locals init (class TryCatchTest.SomeException V_0,
           bool V_1)
  IL_0000:  nop
  .try
  {
    IL_0001:  nop
    IL_0002:  call       void TryCatchTest.Program::FooBar()
    IL_0007:  nop
    IL_0008:  ldc.i4.1
    IL_0009:  stloc.1
    IL_000a:  leave.s    IL_001d
  }  // end .try
  catch TryCatchTest.SomeException
  {
    IL_000c:  stloc.0
    IL_000d:  nop
    IL_000e:  ldloc.0
    IL_000f:  call       void TryCatchTest.Program::LogException(class [mscorlib]System.Exception)
    IL_0014:  nop
    IL_0015:  nop
    IL_0016:  leave.s    IL_0018
  }  // end handler
  IL_0018:  nop
  IL_0019:  ldc.i4.0
  IL_001a:  stloc.1
  IL_001b:  br.s       IL_001d
  IL_001d:  nop
  IL_001e:  ldloc.1
  IL_001f:  ret
} // end of method Program::Test2
.method private hidebysig static bool  Test3() cil managed
{
  // Code size       34 (0x22)
  .maxstack  1
  .locals init (bool V_0,
           class TryCatchTest.SomeException V_1,
           bool V_2)
  IL_0000:  nop
  IL_0001:  ldc.i4.0
  IL_0002:  stloc.0
  .try
  {
    IL_0003:  nop
    IL_0004:  call       void TryCatchTest.Program::FooBar()
    IL_0009:  nop
    IL_000a:  ldc.i4.1
    IL_000b:  stloc.0
    IL_000c:  nop
    IL_000d:  leave.s    IL_001b
  }  // end .try
  catch TryCatchTest.SomeException
  {
    IL_000f:  stloc.1
    IL_0010:  nop
    IL_0011:  ldloc.1
    IL_0012:  call       void TryCatchTest.Program::LogException(class [mscorlib]System.Exception)
    IL_0017:  nop
    IL_0018:  nop
    IL_0019:  leave.s    IL_001b
  }  // end handler
  IL_001b:  nop
  IL_001c:  ldloc.0
  IL_001d:  stloc.2
  IL_001e:  br.s       IL_0020
  IL_0020:  ldloc.2
  IL_0021:  ret
} // end of method Program::Test3

The third way is longest and I think also least readable (taking into account it’s C#). Also you can easily break the code. The first and second are really close in terms of code. The first one I’m using if I like to state, that after the exception is processed, nothing is going on further – “do, return or catch, return, done”. Nor in catch block, nor after it. The second one I’m using if my code is like “do something and return something” and then “else recover based on error and return fallback result”.

And what’s your preference?