51

I have the follow code but it is awkward. How could I better structure it? Do I have to make my consuming class implement IDisposable and conditionally construct the network access class and dispose it when I am done?

    protected void ValidateExportDirectoryExists()
    {
        if (useNetworkAccess)
        {
            using (new Core.NetworkAccess(username, password, domain))
            {
                CheckExportDirectoryExists();
            }
        }
        else
        {
            CheckExportDirectoryExists();
        }
    }
3
  • 4
    Why is it awkward? Looks pretty straight forward to me. Commented Dec 8, 2010 at 16:19
  • 3
    @Joel Etherton: Probably because of the repetition of that CheckExportDirectoryExists() call. Commented Dec 8, 2010 at 16:20
  • 7
    If that is the most awkward bit of your code, you're very well off. Commented Dec 8, 2010 at 16:22

10 Answers 10

93

One option, which is somewhat nasty but would work, based on the fact that the C# compiler calls Dispose only if the resource is non-null:

protected void ValidateExportDirectoryExists()
{
    using (useNetworkAccess 
               ? new Core.NetworkAccess(username, password, domain)
               : null)
    {
        CheckExportDirectoryExists();
    }
}

Another alternative would be to write a static method which returned either null or a NetworkAccess:

private Core.NetworkAccess CreateNetworkAccessIfNecessary()
{
    return useNetworkAccess
        ? new Core.NetworkAccess(username, password, domain)) : null;
}

Then:

protected void ValidateExportDirectoryExists()
{
    using (CreateNetworkAccessIfNecessary())
    {
        CheckExportDirectoryExists();
    }
}

Again, I'm still not sure I don't prefer the original... it really depends on how often you need this pattern.

Sign up to request clarification or add additional context in comments.

8 Comments

You have the logic there backwards. Swap null and the new expression.
Original is prettier, but +1 anyway :)
I didn't know that about using null in the using statement.
@John: I probably wouldn't have done in VS, but I don't like code wrapping on Stack Overflow, which has short lines.
+1 I actually like this a lot. Didn't consider using 'null' before for this, it actually makes things clearer in my situation here because the method call has a bunch of parameters.
|
16

The using statement is a shortcut to avoid "finally" blocks and should only be used when it makes the code easier to follow. In your case I would write the following code. It may not be as brief as some of the other versions, but is much more straight forward.

protected void ValidateExportDirectoryExists()
{
    Core.NetworkAccess access = useNetworkAccess ? new Core.NetworkAccess(username, password, domain) : null;    

    try
    {
        CheckExportDirectoryExists()
    }
    finally
    {
       if (access != null)
       {
           access.Dispose();
       }
    }
}

4 Comments

I would agree, I think this is more intention revealing than the using statement - just because it's immediately obvious that access is optional, because of that null check in the finally statement - where as a using statement obfuscates the intention a little.
i think this is the best answer only because it does the best job of showing intent while doing what is needed without being "clever" in any way. this would be the idiomatic C# way imo.
You are initializing your disposable resource outside of the try/finally. This is clearly not a good idea.
If the object's constructor fails you will not be able to dispose it. Here is a link from the Microsoft site how the using statement is implemented behind the scenes: learn.microsoft.com/en-us/dotnet/csharp/language-reference/…
6

If you repeat this pattern in many methods you can break out the pattern

protected void OptionalNetworkCall(Action action)
{
    if (useNetworkAccess)
    {
        using (new Core.NetworkAccess(username, password, domain))
        {
            action();
        }
    }
    else
    {
        action();
    }
}

protected void ValidateExportDirectoryExists()
{
    OptionalNetworkCall(CheckExportDirectoryExists);
}

1 Comment

This is, most likely, precisely what OP wanted to avoid.
4
protected void ValidateExportDirectoryExists()
{
      var access = useNetworkAccess
          ? new Core.NetworkAccess(username, password, domain)
            : null;

      using (access)
      {
          CheckExportDirectoryExists();
      }
}

Comments

1

I don't know if it is "better", but you could use the null object pattern and have a "null" disposable network access object. Something like this:

protected void ValidateExportDirectoryExists()     
{
  using (GetNetworkAccess(username, password, domain))
  {                 
    CheckExportDirectoryExists();
  }
} 

protected IDisposable GetNetworkAccess(string username, string password, string domain)
{
  return useNetworkAccess ? new Core.NetworkAccess(username, password, domain) : new NullNetworkAccess(username, password, domain);
}

internal class NullNetworkAccess : IDisposable
{
  internal NullNetworkAccess(string username, string password, string domain)
  {
  }

  public void Dispose()
  {
  }
}

This is probably too cute for its own good.

[EDIT] Just saw in Jon's answer that null can be used in a using statement. I had no idea!

Comments

0

using scope will only dispose a object if the class implements IDisposible interface so yes you need to implement dispose method.

Comments

0

I guess that is really a matter of cosmetics if the code is as simple as that.

I can envision how it could look the other way, and my vote will be for this version you have now.

Comments

0

Whatever is enclosed within the using statement will have it's IDispoable.Dispose called as dictated by the IDisposable interface. As seen on MSDN for using...

Provides a convenient syntax that ensures the correct use of IDisposable objects.

Therefore if you put a custom type within the using statement it should clean up its resources appropriately via the IDisposable interface.

Comments

0

By having your class implement IDisposable, the dispose method is called only when using the "using" statement. Otherwise you have to explicitly call dispose.

Typically IDisposable is implemented by objects that manage memory consumption outside of the garbage collector (like using unmanaged code for example). It provides a way to clean up any consumed memory.

So long as your NetworkAccess class implements IDisposable, the dispose method will get called as soon as the scope of the using statement is complete. If it is managed code, then no need to dispose of it. Just let the garbage collector do its work.

Comments

0

Use your own try/finally block, which performs similar logic to the 'using', but only does the dispose if useNetworkAccess is set. Note that if useNetworkAccess could be affected by other threads, you should copy its value and use that copy both for creating the resource and disposing it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.