4

Given a situation like this:

using (var foo = CreateFoo()) {
    if (foo != null) {
        // do stuff
    }
}

I would like to avoid the nested if. Sadly, the obvious solution is not possible because break does not work with using:

using (var foo = CreateFoo()) {
    if (foo == null) {
        break;
    }
    // do stuff
}

Is there a pattern to still avoid the additional indentation caused by the if != null?

mafu
  • 31,798
  • 42
  • 154
  • 247

8 Answers8

6

If you have sufficient control over the class returned from CreateFoo() you could just implement a Null Object and return this instead of the actual NULL value

yas4891
  • 4,774
  • 3
  • 34
  • 55
3

I favor small clearly named methods:

public void DoWhatEver()
{
   using (var foo = CreateFoo())
   {
     if (foo == null) return;

     //DoWhatEver
   }
}
Ritch Melton
  • 11,498
  • 4
  • 41
  • 54
3

Introduce a helper method that takes a lambda. So your code becomes:

UsingIfNotNull(CreateFoo(), foo => {
  //do stuff
});

which has the indentation you want. The definition of UsingIfNotNull is:

public static void UsingIfNotNull<T>(T item, Action<T> action) where T : class, IDisposable {
  if(item!=null) {
    using(item) {
      action(item);
    }
  }
}
Corey Kosak
  • 2,615
  • 17
  • 13
1

This is just a style issue ... code is fine. Are you really that worried about indents? Here's another way to lose the indents anyway ...

public void DoWhatEver()
{
   using(var foo = CreateFoo())
   {
       DoStuffWithFoo(foo);
   }

}

private void DoStuffWithFoo(Foo foo)
{
    if(foo == null) return;

    //DoWhatEver

}
iDevForFun
  • 978
  • 6
  • 10
0

In that sort of generic sense, I believe I would wrap the using in a try...catch block and throw an exception if the object was null, but that's a personal preference.

Jeremy Holovacs
  • 22,480
  • 33
  • 117
  • 254
  • In this case, I explicitly want to fail silently for null objects. – mafu Sep 22 '11 at 13:11
  • well, you could throw the exception, catch it, and do nothing with it, although that's probably not what you want if you would like to fail silently; that has a resource impact and it sounds like the null object is an expected sort of thing. That being said, maybe you should focus on not trying to instantiate something that cannot be instantiated? – Jeremy Holovacs Sep 22 '11 at 13:21
  • Yes, and it would also not improve readability, which is the focus of this question :) – mafu Sep 22 '11 at 13:27
  • The CreateFoo method is sadly not guaranteed to succeed and there is no way to change it, and if it happens to fail it's not critical and must be ignored. (In fact, it just tries to open a file that may be locked right now.) – mafu Sep 22 '11 at 13:29
0

It's an ugly hack, but it avoids the additional identation:

do using (var foo = CreateFoo()) {
    if (foo == null) {
        break;
    }
    // do stuff
} while (false);

(No, I don't recommend to do this. This is just a proof-of-concept to show that it's possible.)

If possible, I would suggest to refactor your code instead:

 using (var foo = CreateFoo()) {
    if (foo != null) {
        doSomethingWith(foo);  // only one line highly indented
    }
}
Heinzi
  • 167,459
  • 57
  • 363
  • 519
0

Personally I would probably leave the code as you've posted it.

However, since you asked (and at the risk of exposing myself to downvotes to this often-maligned language feature), you could always use "goto":

using (var foo = CreateFoo()) {
    if (foo == null) {
        goto SkipUsingBlock;
    }
    // do stuff
}

SkipUsingBlock:
// the rest of the code...
JohnD
  • 14,327
  • 4
  • 40
  • 53
  • As first year students of IT, were cursed upon every time we barely even whispered 'goto'. They have covered our eyes when there was a possibility to see 'goto code'. – Krzysztof Jabłoński Jan 23 '13 at 23:31
0

C# compiler treats using(var foo = CreateFoo()) statement in:

try
{
var foo = CreateFoo();
}
finally
{
  ((IDisposable) foo).Dispose();
}

If your method CreateFoo return not disposable object - do not use using at all. In other case you can write:

try
{
var foo = CreateFoo();
//do stuff like foo.SomeMethod (if foo == null exception will be thrown and stuff will not be done)
}
finally
{
  ((IDisposable) foo).Dispose();
}
Tadeusz
  • 6,453
  • 9
  • 40
  • 58
  • This does not help because there is still no way to break to avoid the indentation. – mafu Sep 22 '11 at 13:23
  • Also, for reference, the description seems inaccurate: `foo` should be enclosed in a new block in outer scope, and there is a null check in finally. – mafu Sep 22 '11 at 13:24