views:

183

answers:

5

I'd like to know your opinion on a matter of coding style that I'm on the fence about. I realize there probably isn't a definitive answer, but I'd like to see if there is a strong preference in one direction or the other.

I'm going through a solution adding using statements in quite a few places. Often I will come across something like so:

{
    log = new log();
    log.SomeProperty = something;  // several of these
    log.Connection = new OracleConnection("...");
    log.InsertData(); // this is where log.Connection will be used
    ... // do other stuff with log, but connection won't be used again
}

where log.Connection is an OracleConnection, which implements IDisposable.

The neatnik in me wants to change it to:

{
    using (OracleConnection connection = new OracleConnection("..."))
    {
        log = new log();
        log.SomeProperty = something;
        log.Connection = conn;
        log.InsertData();
        ...
    }
}

But the lover of brevity and getting-the-job-done-slightly-faster wants to do:

{
    log = new log();
    log.SomeProperty = something; 
    using (log.Connection = new OracleConnection("..."))
        log.InsertData();
    ...
}

For some reason I feel a bit dirty doing this. Do you consider this bad or not? If you think this is bad, why? If it's good, why?

EDIT: Please note that this is just one (somewhat contrived) example of many. Please don't fixate on the fact that this happens to indicate a logger class with a poorly thought-out interface. This is not relevant to my question, and I'm not at liberty to improve the classes themselves anyway.

+3  A: 

I would listen to the neatnik in you. I like his way better personally.

Josh Einstein
-1 ... but why?
Eric Mickelsen
Because the second way just looked very ugly to me and I am very particular about the way code "looks".
Josh Einstein
Okay fine, un -1 for honesty.
Eric Mickelsen
It's ok I figured there's no right answer to this question which is why I marked my answer community wiki. :)
Josh Einstein
+4  A: 

They are both horrid. Do neither of them.

You're making what I call a "high maintenance class" here. The high maintenance class has a contract that says "I require you to give me a bunch of resources, and you're required to know when I'm done with them and clean them up appropriately". This contract means that the user of the class has to know how the class is implemented, thereby violating the principle of encapsulation and abstraction that motivated making a class in the first place.

You can tell this by your comment: this is where the connection is used, I know the connection will not be used again. How do you know that? You only know that if that is the documented contract of the class. That's not a good contract to impose upon the consumer of a class.

Some ways to make this better:

1) make the logger disposable. Have it clean up the connection when it is done. The down side of this is that the logger holds on to the connection for longer than necessary.

2) make InsertData take the connection as a parameter. The caller can still be responsible for cleaning up the connection because the logger does not hold onto it.

3) make a third class "Inserter" which is disposable and takes a log and a connection in its constructor. The inserter disposes of the connection when it is disposed; the caller then is responsible for disposing the inserter.

Eric Lippert
That's interesting because the rule of thumb most of the time I've found to be "If you create it, it's your job to dispose of it." I would be more surprised to see the logger dispose of a connection that may or may not be shared by other loggers. As an example, it's been a while since I used SqlCommand directly, but if I recall, it does not dispose the connection you pass to it.
Josh Einstein
@Josh: If you want to share, do option #2. The connection just shouldn't be a member of log.
Eric Mickelsen
@Josh: Compare that to stream readers, which do own disposal of the stream they are reading. What's important is that the contract not be (1) difficult or (2) surprising. I would be surprised to find that a logger was holding on to a reference to a disposed collection; how do I know that the logger is done with it?
Eric Lippert
Unfortunately, making those improvements is out of the scope of my current task. There are a great many such changes I would love to make in this solution, but I'm not currently assigned to do so. However, this was just one example of many. Some of the other cases do conform to your second suggestion already. These things considered, I'd still like your opinion as to my original question.
Charles
@Eric, fair enough but then there's NetworkStream which gives you an explicit option in the constructor as to whether or not you are giving it "ownership" of the socket. I like your #2 suggestion but #1 seems just as vague to me.
Josh Einstein
A: 

If log implements IDisposable, then do the second choice, as the braces are explicit. In some cases you can use multiple using statements:

using (Graphics g = ...)
using (Pen p = new Pen ...)
using (Font f = new Font ...)
{



}

where you can get away with only using 1 set of braces. This avoids crazy indents.

Charlie Salts
log doesn't implement IDisposable. With that in mind, would you prefer the "neat" first choice?
Charles
Then go with Eric Lippert's suggestions. He's pretty much the horse's mouth in this area.
Charlie Salts
Eric's suggestions would be great if I was the one authoring the classes using the connection, but he didn't suggest anything that addressed my actual question.
Charles
If `OracleConnection` implements IDisposable, then go with your last option.
Charlie Salts
+1  A: 

The two ways of using using are totally equivalent. Either way, you end up with a log that's still in scope but has a disposed connection. It's way better to make the log disposable and have its dispose method dispose of its connection, putting the log in the using statement, not the connection itself.

Eric Mickelsen
Agreed, this example shows a poor interface, but let's leave that aside for now. I realize the two ways are equivalent, but do you have a gut preference for either way?
Charles
@Charles: My gut tells me the reason you are facing this dilemma is a poor original design choice (making the connection a member). If you really can't undo that choice, I would still to neither. I would do something close to #1, but I would put the log object entirely within the scope of the using block so that you can't try to use it after the connection is disposed.
Eric Mickelsen
Yes, the reality of being a a programmer for hire is that you face this dilemma on a daily basis, and more often than not, are unable to correct the underlying issue. This is a fact that I regularly see apparently seasoned developers on SO fail to grasp. Your point about moving all reference of the connection-consuming object inside the using block, to prevent the possibility of it using the connection after being disposed, is a good thought. Thanks for your input.
Charles
+1  A: 

I agree that ideally log itself should implement IDisposable, but let's assume that's not possible and address the question the OP actually asked.

The second way is better, simply because it's less code that accomplishes the same thing. There is no advantage to introducing an additional connection variable here.

Also note that you could do other initialisation outside of the using block. It won't matter here, but may matter if you're "using" some really expensive resource. That is:

log = new log();
log.SomeProperty = something; // This can be outside the "using"
using (OracleConnection connection = new OracleConnection("..."))
{
    log.Connection = conn;
    log.InsertData();
    ...
}
Evgeny
Thank you for addressing the actual question. Your point about performing the initialization outside of the using block is interesting, because the only reason I moved it inside the block was that I felt it was neater to keep all the related code together. I hadn't thought of the potential expense (not an issue here, but a valid point to keep in mind).
Charles