Click here to Skip to main content
15,880,796 members
Please Sign up or sign in to vote.
3.75/5 (4 votes)
See more:
Hi,

I'd like to hear your opinions on conditional using blocks. The thing is that I need to have a structure like the following:
C#
public void AMethod(bool useClass2) {
   using (Class1 variable1  = new Class1()) {
      using (Class2 variable2 = new Class2(variable1) {
         using (Class3 variable3 = new Class3(variable2) {
            variable3.DoSomething();
         }
      }
   }
}

Now the problem is that based on the parameters of the method the middle using block should either be included or excluded. If the parameter useClass2 is true, the code should be executed as above but if the parameter is false, then the execution should look like the following:
C#
public void AMethod(bool useClass2) {
   using (Class1 variable1  = new Class1()) {
         using (Class3 variable3 = new Class3(variable1) {
            variable3.DoSomething();
         }
   }
}

So based on the parameter, the middle using block may be included and the innermost using block uses either Class1 or Class2.

Now, this could be done with for example:

  • Separate, specialized methods (no need for parameter)
  • using If..Else structure for the Class2, and duplicating the inner code on necessary parts etc.

But I'm curious, am I missing something obvious? Would there be an easy, clean way to conditionally use or bypass the instance of the Class2?

The classes (1-3) are .Net framework classes derived from File.IO.Stream, for example FileStream, CryptoStream etc.
Posted
Updated 12-Sep-12 7:00am
v2
Comments
Sergey Alexandrovich Kryukov 13-Sep-12 22:58pm    
Hi Mika,
How it's going?

Here is the news: I decided to write a short article on this question. I submitted it as a Tips & Tricks article, but by some reason it appeared in Articles section. I provided some of a bit more of in-depth analysis and the source code for the approached I already mentioned in my answer. Here:
http://www.codeproject.com/Articles/458846/Using-using-Statements-DisposalAccumulator

I credited you for all of the inspiration you gave by this interesting question and remarkable example.

Best wishes,
--SA

I think separate methods is the way to go. At the very least, the names of those methods could make it more obvious what's going on. Or, if there's no significant penalty to using Class2 even when it's not needed, just use the first.
 
Share this answer
 
Comments
Wendelius 12-Sep-12 13:27pm    
Yes, that's one option. In that case I need to duplicate parts of the code but fortunately that's not actually very much.

There's no (notable) penalty regarding to performance for using the middle stream, it's just unwanted functionality in that scenario. :)
lewax00 12-Sep-12 14:33pm    
I've done some weird tricks to avoid duplications in the case of re-used using statements with lambdas, it can be a bit awkward though. In the end it doesn't save you much typing, but it can make refactoring easier.
Sergey Alexandrovich Kryukov 12-Sep-12 20:20pm    
I think the core thing is: your answer missed the important detail: some essential ambiguity in the question which I explain in my answer -- please see. Good question, anyway.
--SA
Sergey Alexandrovich Kryukov 13-Sep-12 22:59pm    
By the way, I decided to publish a short article on this topic. Please see:
http://www.codeproject.com/Articles/458846/Using-using-Statements-DisposalAccumulator
--SA
Wendelius 14-Sep-12 13:49pm    
I think still is a good way especially if there's also another parts in the method that are not common. So 5 from me
Very interesting question, but yes, you are missing something.

Your code sample may mean the different things. Look at the constructor Class2.Class2. It may mean:

Single constructor based on late binding of the type Class1:
C#
class Class1 : IDisposable {/* ... */}

class Class2 : IDisposable {
   internal Class2(Class1 variable) {/* ... */}
   //...
}

// which is based on this inheritance:
class Class2 : Class1, IDisposable {/* ... */}


The same code fragments could be implemented in different content, where the classes Class1 and Class2 are unrelated:
C#
class Class2 {
   internal Class2(Class1 variable) {/* ... */}
   internal Class2(Class2 variable) {/* ... */}
   //...
}


Are you starting to get it? If you use polymorphism, you can optimize your code and avoid "if":
C#
static void AMethod(bool useClass2) {
    using (Class1 variable1 = new Class1()) {
        Class1 factoryParameter = null;
        if (useClass2)
            factoryParameter = variable1;
        using (Class1 variable2 = Class1Factory(factoryParameter)) {
            using (Class3 variable3 = new Class3(variable2)) {
                variable3.DoSomething();
            } //variable3 is disposed here
        } //variable2 is disposed here
    } //variable1 is disposed here
} //AMethod

static Class1 Class1Factory(Class1 factoryParameter) { // important: late-bound return type
    if (factoryParameter == null)
        return new Class1();
    else
        return new Class2(factoryParameter);
} //Class1Factory


What to do in the more general case, when those IDisposable classes/structures are unrelated? You can leave your "naive" separate implementation putting both samples together with one "if" operator, but it could look too much messed up if you have greater level of nesting (which easily can be the case).

There is another way of doing thing. First, the using statement is equivalent to some try-finally block (or nested blocks). You can literally use it; it can be more compact then using, because try-finally is more general. But you can also use the special and well known technique:

Create a special "DisposalAccumulator" class which can accumulate all instances to be disposed in some container. This class should also implement IDisposable, to be used in one single using statement. Create only the instance of such class under using with only one level of nesting. Do you need to explain you more? I thing you should get an idea. If not just yes, your follow-up questions are very welcome — it's always a pleasure to deal with correctly formulated and sensible questions.

[EDIT #1]

I think most important criterion here would be to avoid any repeated code. I think you understand it. Please see:
http://en.wikipedia.org/wiki/Don%27t_repeat_yourself[^].

[EDIT #2]

Hold on, I'll try to provide code samples for those two general-case solutions: try-finally and "DisposalAccumulator", because it may be of some value to other readers.

My very best wishes,
—SA
 
Share this answer
 
v14
Comments
Wendelius 14-Sep-12 13:46pm    
Yes, this would be a feasible solution especially with own classes. Definitely a five.
Sergey Alexandrovich Kryukov 14-Sep-12 14:25pm    
Thank you, Mika.
--SA
I landed here via the article[^] proposed by Sergey, but I'm sure you'd like to see my solution as well.

You can actually assign null values to using statement variables. The syntactic sugar for the using block actually checks for a null variable in the finally block prior to a dispose. So, per Sergey's example, I provided the following solution that reduces redundant code and doesn't require the need for an additional class:

C#
static void NotSoNaiveWay(bool createSecond)
{
    using (First first = new First())
    using (Second second = (createSecond) ? new Second(first) : null)
    using (Third third = (createSecond) ? new Third(second) : new Third(first))
    {
        third.DoSomething();
    }
}


If you made the Third class dispose of any provided IDisposable elements, you could simplify this further to:

C#
static void NotSoNaiveWay(bool createSecond)
{
    using (First first = new First())
    using (Third third = (createSecond) ? new Third(new Second(first)) : new Third(first))
    {
        third.DoSomething();
    }
}


I hope that helps.
 
Share this answer
 
Comments
Wendelius 14-Sep-12 13:51pm    
Thanks, I actually was thinking the same :) The only concern I have is that this solution relies on the fact that Dispose isn't called for a null. This is current behaviour in .Net but could this be a potential breaking change...

Anyhow, this works nicely currently so a 5.
Andrew Rissing 14-Sep-12 14:06pm    
I don't believe I've heard any mumblings of this behavior changing any time soon. So, you are likely safe for sometime.

Btw, are you using this to conditionally encrypt/compress your output? Or is this for something else?
Wendelius 14-Sep-12 15:28pm    
Basically this is for a project I'm working with which includes compression and encryptions so a good guess :)

As a spin-off I was thinking about using it on the article I updated: Encrypting a dataset using AES, including compression[^] but then I decided not to, since I believe that it would have (possibly) been harder to read.
Andrew Rissing 14-Sep-12 15:58pm    
Cool. I will say though that GZipStream and CryptoStream both dispose of any Stream objects passed to them, so the use of layered using statements would be redundant. Worst case scenario, if the dispose method failed to complete successfully (an entirely exceptional situation here), the finalize method would eventually kick in as a saving grace.

Food for thought.
Wendelius 14-Sep-12 16:05pm    
Thanks, that's really messing my brains in late Friday night (local time) :)

Now professionally, yes you're right, it would be redundant but since they are disposed in correct order I also think that the finalizer will handle the situation :)
In this case I would probably have separate public methods and call a common private method if you need to reduce code duplication. An option would be to use a generic in the private class. Can also just use the generic in a public class. Here is the general concept:

public void Test1 ()
{
    Test<test1>();
}

public void Test2()
{
    Test<test2>();
}

private void Test<T> () where T : IDisposable, new()
{
    using (var x = new T())
    {

    }
}
 
Share this answer
 
Comments
Wendelius 12-Sep-12 14:12pm    
Hmm, yes that could work fine in this situation. Converting the idea to the example I wrote, I'd actually link the methods and make the decision which method to use in the outermost using block.

What I need to check is that can I use the base class definition (Stream in this case) in the innermost method and still achieve the same functionality. If this would be true, I could use this idea to reduce the code duplication.

Of course on the other hand this raises the complexity a bit but I'm curious to see how it actually turns out :)
Clifford Nelson 12-Sep-12 15:01pm    
To ensure that it is a stream, obviously add to the where clause. The complexity, I think, is actually less. The streams already support IDisposable. Also, can just make the Test<t> public, which would make it much more flexible, expecially if it is designed to work with any instance of a class that inherits from a base class.
Sergey Alexandrovich Kryukov 12-Sep-12 20:22pm    
Good point, but I voted 4, just because it's hard to see how it can improve the code with nesting and depending IDisposable variables. I, for example, cannot see it. I would suggest you demonstrate the use of those 2 vs 3 variables and how they are disposed.

There is another important thing here: some essential ambiguity in the question which I explain in my answer -- please see. Good question, anyway.
--SA
Sergey Alexandrovich Kryukov 13-Sep-12 23:00pm    
By the way, I decided to publish a short article on this topic. Please see:
http://www.codeproject.com/Articles/458846/Using-using-Statements-DisposalAccumulator
--SA
Wendelius 14-Sep-12 13:48pm    
Just tested this variation and it works out fine. The only problem that I encountered was that the logic is easily scattered to separate methods (depending on the situation). Anyhow a usable solution in many cases.
Why dont you go for inheritance ?

Class3 > Inherits Class2
Class2 > Inherits Class1

Now Implement Class1 as IDisposable, and you will be able to use Single using statement

Also define proper methods and constructors that act on specific objects.
 
Share this answer
 
Comments
Wendelius 12-Sep-12 12:59pm    
Good point. One thing I forgot to mention is that the classes are actually .Net Framework classes, to be precise, different kinds of streams derived from File.IO.Stream.

I'll update the question
Sergey Alexandrovich Kryukov 12-Sep-12 20:19pm    
Maybe, but, unfortunately, if does not solve the problem per se. Besides, most answers miss the important detail: some essential ambiguity in the question which I explain in my answer -- please see. Good question, anyway.
--SA
Kuthuparakkal 13-Sep-12 1:45am    
You may get more ideas on this by examining open source SharpZipLib classes, they have many classes that inherit from System.IO.Stream:
http://www.icsharpcode.net/opensource/sharpziplib/Download.aspx
Wendelius 13-Sep-12 5:08am    
Thanks! I'll have a look at those.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900