473,385 Members | 1,474 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

Paradigm for multiple IDisposables

I'm sure this comes up often, but I have a situation where I have at
least 4 objects that all implement IDisposable. It gets very tedious
having to write finally blocks that Dispose all of them in a row, but
the using statement is very limited in that it doesn't (seem to) allow
me to have a list of objects specified. Well, I guess that's not
entirely true, if they are all the same type it does, but in my case
they aren't all the same type. I've figured out a couple ways of
handling, but I wonder if there is something more elegant than what I'm
doing. Here's what I've thought of so far:

-------------------------------------
Solution 1: Initialize everything outside of the using block, then use
a list of IDisposables inside the using statement, and the compiler
will implicitly convert each one to an IDisposable, and since they will
all be the same type after implicit conversion, the syntax is allowed.

Example 1:

Disposable1 First = new Disposable1();
Disposable2 Second = new Disposable2();
using (IDisposable dummy1 = First, dummy2 = Second)
{

}
-------------------------------------
Solution 2: Write a new class (MultiDispose), which itself implements
IDisposable and contains a list of classes which implement IDisposable,
and receives a list of items in its constructor. In
MultiDispose.Dispose, run through the list and Dispose() each item in
the list.

Example 2:
class MultiDispose : IDisposable
{
private List<IDisposable_DisposeList;
public MultiDispose(params IDisposable[] DisposeList)
{
_DisposeList = new List<IDisposable>(DisposeList);
}

public void Dispose()
{
foreach (IDispose DisposeItem in _DisposeList)
DisposeItem.Dispose();
}
}

//Some other function
using (MultiDispose DisposeScope = new MultiDispose(First, Second,
Third, Fourth))
{

}
-------------------------------------
Solution 3: Do nothing special, just use tons of nested using
statements. To improve readability, wrap only the innermost using
block with parentheses, and don't indent consecutive using blocks so as
to keep the indentation level small.

Example 3:

using (Disposable1 First = new Disposable1())
using (Disposable2 Second = new Disposable2())
using (Disposable3 Third = new Disposable3())
using (Disposable4 Fourth = new Disposable4())
{
//Code here
}
-------------------------------------
So far I prefer Solution #2 above, because it has the nice benefit of
allowing me to add a method to MultiDispose called Add(), so I can add
a new item to the list in the middle of the block. This provides an
elegant way to Dispose of items which aren't valid unless certain
operations (which could throw) have already been performed on one of
the items declared in the using block. An example with Database code:

SqlConnection Connection = new SqlConnection(ConnectionString);
SqlCommand Command = new SqlCommand(CommandText, Connection);
using (MultiDispose DisposeScope = new MultiDispose(Connection,
Command))
{
Connection.Open();
SqlDataReader Reader =
Command.ExecuteReader(CommandBehavior.CloseConnect ion);

DisposeScope.Add(Reader);
if (!Reader.HasRows)
return false;
//Process the data in the rows.
}

The alternative in this situation would have been to make ANOTHER using
block just for the Reader, which would start to hinder readability, and
possibly performance.

I admit I don't know too much about CLR internals or some of the
intricacies of C# language syntax, so I'm having a hard time analyzing
all the pros and cons of each method. For example, Solution 3 creates
a nesting of try/finally blocks N levels deep, where N is the number of
items you're "using". Perhaps this could have some performance
implications. Solution 2 (my preferred solution so far) could have
some pitfalls in that you're circumventing some of the typical checks
the compiler performs for you, which may make it easier to introduce
subtle programming errors.
Anyone have any thoughts on this problem, or is there a standard
"accepted" way of handling this?

Thanks

Sep 22 '06 #1
3 1573


"Zach" <di***********@gmail.comwrote in message
news:11*********************@k70g2000cwa.googlegro ups.com...
I'm sure this comes up often, but I have a situation where I have at
least 4 objects that all implement IDisposable. It gets very tedious
having to write finally blocks that Dispose all of them in a row, but
the using statement is very limited in that it doesn't (seem to) allow
me to have a list of objects specified. Well, I guess that's not
entirely true, if they are all the same type it does, but in my case
they aren't all the same type. I've figured out a couple ways of
handling, but I wonder if there is something more elegant than what I'm
doing. Here's what I've thought of so far:
.. . .
-------------------------------------
Solution 3: Do nothing special, just use tons of nested using
statements. To improve readability, wrap only the innermost using
block with parentheses, and don't indent consecutive using blocks so as
to keep the indentation level small.

Example 3:

using (Disposable1 First = new Disposable1())
using (Disposable2 Second = new Disposable2())
using (Disposable3 Third = new Disposable3())
using (Disposable4 Fourth = new Disposable4())
{
//Code here
}
-------------------------------------

.. . .
>
Anyone have any thoughts on this problem, or is there a standard
"accepted" way of handling this?
I greatly prefer "Solution 3". It's simple, completely general, readable
and works well.

The performance should be fine, especially since use of Disposable objects
usually coincides with network access, and so performance considerations on
the order of magnitude at which these solutions differ should be irrelevant.

David

Sep 22 '06 #2
Zach,

Right now, what you have, only solution three is guaranteed to protect
you and call IDisposable in the face of exceptions.

The problem with #1 is that if an exception is thrown on the call to the
constructor for Disposable2, then the stack is excited, and the instance of
Disposable1 isn't disposed of properly.

#2 won't work for the same reason. If you do this:

Disposable1 d1 = new Disposable1();
Disposable2 d2 = new Disposable2();

using (MultiDispose md = new MultiDispose(d1, d2))
{
}

You run into the same problem above. Even if you do this:

using (MultiDispose md = new MultiDispose(new Disposable1(), new
Disposable2))

You still have the problem, since the call to the constructor of
Disposable2 can throw.

You can adapt solution 2 so that the constructor takes nothing. Then,
you can call Add ^inside^ the using block, like so:

Disposable d1 = null;
Disposable d2 = null;

using (MultiDispose md = new MultiDispose())
{
md.Add(d1 = new Disposable1());
md.Add(d2 = new Disposable2());
}

That will work, because if one of the calls to the constructors throws,
then you know that things will be disposed of properly.

One other thing to make sure this works. In your implementation of
IDisposable on MultiDispose, you have to wrap the call to Dispose on each
item in a try/catch and re-throw the exception if one is thrown during a
call to Dispose. Then, for good measure, you should probably re-throw
whatever exceptions you catch (or just the first one, if you catch more than
one).

All that being said, I think you can see why #3 is the best solution.

Hope this helps.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Zach" <di***********@gmail.comwrote in message
news:11*********************@k70g2000cwa.googlegro ups.com...
I'm sure this comes up often, but I have a situation where I have at
least 4 objects that all implement IDisposable. It gets very tedious
having to write finally blocks that Dispose all of them in a row, but
the using statement is very limited in that it doesn't (seem to) allow
me to have a list of objects specified. Well, I guess that's not
entirely true, if they are all the same type it does, but in my case
they aren't all the same type. I've figured out a couple ways of
handling, but I wonder if there is something more elegant than what I'm
doing. Here's what I've thought of so far:

-------------------------------------
Solution 1: Initialize everything outside of the using block, then use
a list of IDisposables inside the using statement, and the compiler
will implicitly convert each one to an IDisposable, and since they will
all be the same type after implicit conversion, the syntax is allowed.

Example 1:

Disposable1 First = new Disposable1();
Disposable2 Second = new Disposable2();
using (IDisposable dummy1 = First, dummy2 = Second)
{

}
-------------------------------------
Solution 2: Write a new class (MultiDispose), which itself implements
IDisposable and contains a list of classes which implement IDisposable,
and receives a list of items in its constructor. In
MultiDispose.Dispose, run through the list and Dispose() each item in
the list.

Example 2:
class MultiDispose : IDisposable
{
private List<IDisposable_DisposeList;
public MultiDispose(params IDisposable[] DisposeList)
{
_DisposeList = new List<IDisposable>(DisposeList);
}

public void Dispose()
{
foreach (IDispose DisposeItem in _DisposeList)
DisposeItem.Dispose();
}
}

//Some other function
using (MultiDispose DisposeScope = new MultiDispose(First, Second,
Third, Fourth))
{

}
-------------------------------------
Solution 3: Do nothing special, just use tons of nested using
statements. To improve readability, wrap only the innermost using
block with parentheses, and don't indent consecutive using blocks so as
to keep the indentation level small.

Example 3:

using (Disposable1 First = new Disposable1())
using (Disposable2 Second = new Disposable2())
using (Disposable3 Third = new Disposable3())
using (Disposable4 Fourth = new Disposable4())
{
//Code here
}
-------------------------------------
So far I prefer Solution #2 above, because it has the nice benefit of
allowing me to add a method to MultiDispose called Add(), so I can add
a new item to the list in the middle of the block. This provides an
elegant way to Dispose of items which aren't valid unless certain
operations (which could throw) have already been performed on one of
the items declared in the using block. An example with Database code:

SqlConnection Connection = new SqlConnection(ConnectionString);
SqlCommand Command = new SqlCommand(CommandText, Connection);
using (MultiDispose DisposeScope = new MultiDispose(Connection,
Command))
{
Connection.Open();
SqlDataReader Reader =
Command.ExecuteReader(CommandBehavior.CloseConnect ion);

DisposeScope.Add(Reader);
if (!Reader.HasRows)
return false;
//Process the data in the rows.
}

The alternative in this situation would have been to make ANOTHER using
block just for the Reader, which would start to hinder readability, and
possibly performance.

I admit I don't know too much about CLR internals or some of the
intricacies of C# language syntax, so I'm having a hard time analyzing
all the pros and cons of each method. For example, Solution 3 creates
a nesting of try/finally blocks N levels deep, where N is the number of
items you're "using". Perhaps this could have some performance
implications. Solution 2 (my preferred solution so far) could have
some pitfalls in that you're circumventing some of the typical checks
the compiler performs for you, which may make it easier to introduce
subtle programming errors.
Anyone have any thoughts on this problem, or is there a standard
"accepted" way of handling this?

Thanks

Sep 22 '06 #3
This may also be of help...

http://www.geocities.com/jeff_louie/oop29.htm

Regards,
Jeff

*** Sent via Developersdex http://www.developersdex.com ***
Sep 22 '06 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Florian Weimer | last post by:
I'd like to get up to speed with multi-paradigm design with C++. Can you recommend any books on this topic? I'd prefer something which is not tied to a particular compiler, treats ISO C++, and is...
0
by: Frnak McKenney | last post by:
Evert: verb. Turn inside out; turn the inner surface of outward. The project I'm working on involves seven or eight reports. They vary from simple ("print this field here, that there, with a...
4
by: Jared Thirsk | last post by:
== Introduction to DAF == I am interested in the next generation of approaches to software development. Over the last decades, there has been an obvious shift in how our most complex software...
0
by: Ralph | last post by:
I´m planning on purchasing Visual Paradigm SDE (UML) product integrated with VS .NET, Have somebody used it?, any comments? (It seems to be a very powerfull UML tool, and it´s an specilized...
1
by: The Garbage Collector | last post by:
Hey guys, Heres something I used to do very commonly in java, and I'm having a hard time coming up with a good paradigm for how to manage this in c#. In Java, to show data on a grid, you need to...
1
by: A Mackie | last post by:
Service Oriented Architecture (SOA) - a great new paradigm, or just this years marketing snake-oil for middleware vendors ? Now don't get me wrong, integration of loosely coupled web-services...
1
by: bobwooderton | last post by:
Either I am using the wrong approach or I just don't get it. so, the 'this' in 'this.changeState()' on the second to last line of the constructor code refers to the object _referObject, instead of...
2
by: Roshan Naik | last post by:
Castor is a pure C++ Library that introduces the Logic paradigm (LP) into C++. Although LP has been well explored in Computer science, it remains under utilized in main stream software...
3
by: Israel | last post by:
I always wondered why the using command can only take one object. I always find that this isn't sufficient for drawing so I end up always disposing in my finally block but then I have to remember...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.