A question of programming style

  • Thread starter Thread starter Mark
  • Start date Start date
M

Mark

Hi

This is a fairly generic question about programming style and to a certain
extent garbage collection. I have some methods that I write to text logs,
the event log etc at various places in the method. What I do is open the
various logs at the start of the method and, being good, I explicitly close
them at the end. In the method, I also catch exceptions at various places.
For some of these exceptions, I wish to exit the method. Now being pedantic,
I also want to close the logs before exiting the method even in the catch
clause. So what I end up with is something like:

private void myMethod()
{
EventLog log = new EventLog(strMyLog);
log.Source = strMySource;
// main block of code here, followed by...
try
{
// some code that might throw an exception
}
catch
{
// some exception code here
log.Dispose();
return;
}

// bit mode code to do stuff here
try
{
// some more code that might throw an exception
}
catch
{
// more exception code here
log.Dispose();
return;
}

// final code stuff here
log.Dispose();
}

Whilst this works and forces me to do all the tidying up myself, it appears
a bit clunky. So my question is:
- Should I just not bother trying to tidy up and just let the garbage
collector sort everything out? (This goes against the grain!)
- Is there a better way of organizing the code so that I only have one
log.Dispose()?
- Perhaps I should wrap the whole method in a try finally clause? (This
seems a weird option.)
- Am I just worrying about nothing?

TIA
Mark
 
Mark said:
This is a fairly generic question about programming style and to a certain
extent garbage collection. I have some methods that I write to text logs,
the event log etc at various places in the method. What I do is open the
various logs at the start of the method and, being good, I explicitly close
them at the end. In the method, I also catch exceptions at various places.
For some of these exceptions, I wish to exit the method. Now being pedantic,
I also want to close the logs before exiting the method even in the catch
clause. So what I end up with is something like:

<snip>

Firstly, you can use a finally block. This kind of thing is exactly
what a finally block is for. Secondly, you can get it automatically
with the using (...) construct. Your method would become:

private void myMethod()
{
using (EventLog log = new EventLog(strMyLog))
{
log.Source = strMySource;
// main block of code here, followed by...
try
{
// some code that might throw an exception
}
catch
{
// some exception code here
return;
}

// bit mode code to do stuff here
try
{
// some more code that might throw an exception
}
catch
{
// more exception code here
return;
}
}
}
 
[snip]
Firstly, you can use a finally block. This kind of thing is exactly
what a finally block is for.

Thanks for the rapid response. I considered using using (if you know what I
mean!), but often I open a couple of event logs and sometime a few files
(sorry my example only showed a single event log - my mistake). So, I could
wrap each individually in a using statement, but nesting that lot can be
cumbersome? I like the sound of using a finally clause, but where exactly
would it go? I tried a finally on it's own at the end of the method but not
surprisingly it wants a try clause! So I guess that what I really after is
something that looks like this but of course without the "goto":

private void myMethod()
{
log1.Source = strMySource1;
log2.Source = strMySource2;
StreamWriter sw1 = new StreamWriter(strMyFile1, true)
StreamWriter sw2 = new StreamWriter(strMyFile2, true)

// main block of code here, followed by...
try
{
// some code that might throw an exception
}
catch
{
// some exception code here
goto TimeToGetOuttaHere;
}

// bit mode code to do stuff here
try
{
// some more code that might throw an exception
}
catch
{
// more exception code here
goto TimeToGetOuttaHere;
}

// More code goes here

Label: TimeTogetOuttahere
sw2.Close();
sw1.Close();
log2.Dispose();
log1.Dispose();
}

I'm sure that there must be an easy way to achieve this without large
numbers of nested ifs, trys etc, but I just can't see it at the moment! Some
kind of statement that means "run this bit of code before existing the
method, even if we've hit a return statement elsewhere in the method" would
be useful.

Cheers
Mark
 
No offense intended, but methinks you need to read the documentation a bit
on try...catch...finally blocks for an explanation of where to put the
finally part.

Also, you can specify multiple objects in the using statement, according to
the doc example:

using (Font MyFont = new Font("Arial", 10.0f), MyFont2 = new Font("Arial",
10,0f))
{
}

or in your case
using (StreamWriter sw1 = new StreamWriter(strMyFile1, true), sw2 = new
StreamWriter(strMyFile2, true))
{
}

You may also want to look into the concept of trace or debug listeners. It
would make for a much more elegant solution in my opinion, and would add the
option of being able to change logging levels and event logs via a
configuration file. Then your code just needs to say
Trace.WriteLine("blah blah blah");
and it will be written to all the configured event logs.

Mark said:
[snip]
Firstly, you can use a finally block. This kind of thing is exactly
what a finally block is for.

Thanks for the rapid response. I considered using using (if you know what I
mean!), but often I open a couple of event logs and sometime a few files
(sorry my example only showed a single event log - my mistake). So, I could
wrap each individually in a using statement, but nesting that lot can be
cumbersome? I like the sound of using a finally clause, but where exactly
would it go? I tried a finally on it's own at the end of the method but not
surprisingly it wants a try clause! So I guess that what I really after is
something that looks like this but of course without the "goto":
 
Mark said:
Thanks for the rapid response. I considered using using (if you know what I
mean!), but often I open a couple of event logs and sometime a few files
(sorry my example only showed a single event log - my mistake). So, I could
wrap each individually in a using statement, but nesting that lot can be
cumbersome?

If you're opening more than one thing of the same type, you can use:

using (StreamWriter sw1 = new StreamWriter (...),
sw2 = new StreamWriter (...))
{
}

so you don't get as many levels of wrapping.
I like the sound of using a finally clause, but where exactly
would it go?

Round the whole thing, IMO - just leaving the variable declarations for
the things you'll be disposing outside.
I tried a finally on it's own at the end of the method but not
surprisingly it wants a try clause! So I guess that what I really after is
something that looks like this but of course without the "goto":

I think you may be missing the fact that you can have try/finally
without a catch:

log1.Source = strMySource1;
log2.Source = strMySource2;
StreamWriter sw1 = new StreamWriter(strMyFile1, true)
StreamWriter sw2 = new StreamWriter(strMyFile2, true)

try
{
....
}
finally
{
sw2.Dispose();
sw1.Dispose();
log2.Dispose();
log1.Dispose();
}

In this case I'd just use two levels using (...) though.
I'm sure that there must be an easy way to achieve this without large
numbers of nested ifs, trys etc, but I just can't see it at the moment! Some
kind of statement that means "run this bit of code before existing the
method, even if we've hit a return statement elsewhere in the method" would
be useful.

That's exactly what finally does.
 
Daniel Billingsley said:
No offense intended,

None taken
but methinks you need to read the documentation a bit
on try...catch...finally blocks for an explanation of where to put the
finally part.

Sadly, I can see that my biggest problem is making myself understood. Of
course, when I said "where to put the finally clause", I didn't actually
mean "I don't know what a finally clause is". What I actually meant was that
try/catch/finally blocks are intended for when there is an exception that is
or can be thrown. But what if you simply want the benefits of a finally
clause (i.e. "always run this") but without the try bit (i.e. "this code
could generate an exception")? This is bast illustrated with the example
that I provided in my previous posting that uses the dubious concept of a
goto. So, what I'm after is a way to ensure that a block of code is always
run independently of where the method exits.
Also, you can specify multiple objects in the using statement, according to
the doc example:

using (Font MyFont = new Font("Arial", 10.0f), MyFont2 = new Font("Arial",
10,0f))
{
}

or in your case
using (StreamWriter sw1 = new StreamWriter(strMyFile1, true), sw2 = new
StreamWriter(strMyFile2, true))
{
}

Yes, fair point. I see now that there is no such clause in C# as I have
described above, but that the same _effect_ can be acheieved using a using
statement, which will do all the tidying up for me even when there is a
return statement inside the using block. So, what it means is that just
about all the code inside the method is wrapped up in a using statement. I
guess that this is standard practice?
You may also want to look into the concept of trace or debug listeners. It
would make for a much more elegant solution in my opinion, and would add the
option of being able to change logging levels and event logs via a
configuration file. Then your code just needs to say
Trace.WriteLine("blah blah blah");
and it will be written to all the configured event logs.

Nice idea. I used Trace and listeners once before but didn't see the
advantage of using them over simple writing to event logs and text files,
both of which can also be changed via a config file (or in my case, the
registry). However, I'll go back to trying them as I'm sure that they exist
to make my life easier - if only I knew in what way!

Thanks
Mark
 
Jon Skeet said:
If you're opening more than one thing of the same type, you can use:

using (StreamWriter sw1 = new StreamWriter (...),
sw2 = new StreamWriter (...))
{
}

so you don't get as many levels of wrapping.


Round the whole thing, IMO - just leaving the variable declarations for
the things you'll be disposing outside.


I think you may be missing the fact that you can have try/finally
without a catch:

log1.Source = strMySource1;
log2.Source = strMySource2;
StreamWriter sw1 = new StreamWriter(strMyFile1, true)
StreamWriter sw2 = new StreamWriter(strMyFile2, true)

try
{
...
}
finally
{
sw2.Dispose();
sw1.Dispose();
log2.Dispose();
log1.Dispose();
}

In this case I'd just use two levels using (...) though.


That's exactly what finally does.

I understand now - I think! From Daniel Billingsley's reply, he's suggesting
wrapping it all up in a single using statement - which will do the disposing
for me. However from what you're saying, if I wish to take it further and do
some manual tidying up, I can wrap most of my code - including the stuff
that's nothing to do with generating exceptions - in a try statement, and
then do the tidying up in a finally statement. My problem was simply that
I've always taken try/catch/finally to be ways to handle exceptions mainly
because all the examples and my reference book only use them in the context
of throwing and handling exceptions ("try-block Contains the code segment
expected to raise the exception" is an excerpt from MSDN) . However, as you
indicate, this isn't necessarily the case and try could contain anything at
all (or indeed nothing).

Thanks very much for the help
Mark
 
[snip]
Nice idea. I used Trace and listeners once before but didn't see the
advantage of using them over simple writing to event logs and text files,
both of which can also be changed via a config file (or in my case, the
registry). However, I'll go back to trying them as I'm sure that they exist
to make my life easier - if only I knew in what way!

Well I did reaquaint myself to the nuances of Traces etc. One thing that I
notice is that they're OK for sending stuff to a trace file, but when
writing to an event log, there's no way that I can see to change the
EventLogEntryType, e.g. to Warning or Error when sending stuff via a trace
listener.
 
Oh, my mistake.. when you said "I tried a finally on it's own at the end of
the method" before I took it to literally mean you just stuffed a finally {}
at the end of the method with no relation to any try {}. :)
 
Hmmm.. yes I see that. Very unfortunate, eh? I'm guessing it just writes
it as an Information type entry as does the WriteEntry(string message)
overload for EventLog. But I can see how that's too limited for "real"
EventLog writing (errors and warnings).
 
Daniel Billingsley said:
Hmmm.. yes I see that. Very unfortunate, eh? I'm guessing it just writes
it as an Information type entry as does the WriteEntry(string message)
overload for EventLog. But I can see how that's too limited for "real"
EventLog writing (errors and warnings).

Yes, that's exactly what it appears to do. I do like the Trace functionality
because is behaves "class wide". That is, changes to the listeners in one
method are available to all other methods as well. (I hope I'm making sense
here - I usually don't!) However, I'll stick to using the standard EventLog
class for now for writing to the event log and use the Trace for writing to
(would you believe it) a trace file. Perhaps Microsoft will enhance the
whole trace system in some future .Net release? :-)

Thanks for all your help
Mark
 
THe only enhancement to the trace subsystem would be a built in
System.TraceLogListener that automatically writes the trace messages to the
eventlog.

and since you can implement your own trace listener class then the sky is
the limit...
 
Actually I just saw yesterday that there is a Event Log targetted
TraceListener in the System.Diagnostics namespace...

Cheers!


--
Eric Newton
C#/ASP Application Developer
http://ensoft-software.com/
(e-mail address removed)-software.com [remove the first "CC."]

Eric Newton said:
THe only enhancement to the trace subsystem would be a built in
System.TraceLogListener that automatically writes the trace messages to the
eventlog.

and since you can implement your own trace listener class then the sky is
the limit...

--
Eric Newton
C#/ASP Application Developer
(e-mail address removed)-software.com [remove the first "CC."]

Mark said:
Yes, that's exactly what it appears to do. I do like the Trace functionality
because is behaves "class wide". That is, changes to the listeners in one
method are available to all other methods as well. (I hope I'm making sense
here - I usually don't!) However, I'll stick to using the standard EventLog
class for now for writing to the event log and use the Trace for writing to
(would you believe it) a trace file. Perhaps Microsoft will enhance the
whole trace system in some future .Net release? :-)

Thanks for all your help
Mark

that
 
Yes, but how do you specify the level (Information, Warning, Error) when it
writes an entry?
 
Back
Top