Wednesday, April 13, 2011

Consoles and streams

Just a small .Net thing that's kinda cool.
Lots of people write messages to the console of console apps by using Console.Write()/WriteLine()
If you're really working in a console app, that's great. Of course, the problem is that a lot of these console apps get converted to services or windows apps or web pages or whatever. Console.Write() in an aspx page will actually work and not throw an error, but it adds no value.
Even if you're really working in a true console app, the messages you write often scroll by and get lost.

So lots of people write messages to log files. Typically, someone will creat a "Log" class with a "WriteLog" method or something. I've done this, and it's handy. At one point what was cool is that my Logger class was just a wrapper to Log4Net, so I was able to trap the exceptions, put them into the database and into a local text file at the same time (in case the database was down). I even had a method to accept Exceptions and write them out. Cool stuff.

But what if you're working with old code filled with Console.Write() and you want to avoid a global replace? Or what if you've got developers working with you and just can't break them of the habit of Console.Write()?

I ran across this solution and thought it was worth a post.
The Console.Write uses a Console.Out object under it to actually do the write. Console.Out is just a TextWriter. And it can be overridden. (Don't you *love* OO?) So you can say:
FileStream fs = new FileStream("Test.txt", FileMode.Create);

StreamWriter sw = new StreamWriter(fs);

Console.SetOut(sw);

From that point on, anything that runs within the scope of this will write Console information to the "Test.txt" file. For example, if you do it in the Main of your program, anything in the application will write it's console messages to this file.

I love that. I think it's handy and cool. How do you set it back?

Before you change it, you need to store the old value of Console.Out somewhere, then just re-SetOut() it back to what it was, and all new Console messages go to the Console. So you can have the Main() write a couple things to the Console (starting messsages, etc), then have everything else write to the text file. Then, re-set back to the console to put out the ending messages.

The really cool thing is that the writer doesn't need to be a system object. As long as it implements the same interface as TextWriter, the Console class doesn't care. So I could , for example, take my Logger class and make it implement the TextWriter API, then pass that into the SetOut() and all the console messages would get logged through Log4Net wherever I wanted them. Note that TextWriter is an abstract class, so it's all set up to subclass and override.

Very cool stuff... enjoy,
--kevin

No comments:

Post a Comment