Archive
Don't forget to close StreamWriter
In the midst of all my testing, learning, and blogging, my employer occasionally expects me to write a little code. As a result, I’ve spent most of this week being a productive employee, so you’ll have to wait a little while longer for the LINQ articles. In the meantime, I wanted to share a bone head problem I ran into while working on this new project.
The new project is fairly straight forward: read some data from a database, analyze it, look for inconsistencies, correct the inconsistencies, update the database, log the changes in a text file. OK, there’s more going on, but this is the general gist of things.
Having completed the difficult bits, namely recognizing and correcting “user input irregularities”, I moved on to the seemingly mindless task of writing the before and after information to a log file. How many times have we all done this:
StreamWriter file = File.CreateText(logFileName); foreach (var item in collection) { file.WriteLine("Some Text"); }
Simple, right? I ran a test and opened the text file and all appeared to be well. A few tests later, while viewing the results in Excel 2007, I noticed that the last line was cut off. Surely the problem could not be with Excel, I thought, so I looked at the raw text file, and the last line was cut off so many characters in from the left.
Naturally, all sorts of questions start flying through my head. Can an open StreamWriter only handle so many lines? Or could it be a limitation on number of bytes? Is there some system or program memory setting I’m not aware of? The code was so simple that it had to be something more…
But alas, a little digging quickly led me to the answer: it was in fact my code. I failed to Close the StreamWriter, and so there were bytes that even though I had issued WriteLine(), had not yet been saved (or flushed) to the Text file.
I added Close() and sure enough all my data was written to the text file.
StreamWriter file = File.CreateText(logFileName); foreach (var item in collection) { file.WriteLine("Some Text"); } // Close the StreamWriter to flush all the data to the file! file.Close();
It’s good once in a while to run into something like this: it keeps us humble. Like the Roman Generals of old it reminds us that “we are mortal”.
Cheers, and Merry Christmas.
Vista and Special Folders
Way back in January I posted about using Windows Special Folders for storing application data. Today, while setting up a new Vista PC for my boss, I came across a great reason why this approach is a good idea.
I was installing one of our applications that stores a serialized file in the special folder LocalApplicationData. My boss has a ton of configuration information in his current install of this application, and I thought it would be a good thing to simply copy his current configuration over to his new machine. Hey, anything that makes his life easier makes my life easier!
So I began by copying his binary file to a network location for later retrieval. I then went to his new Vista PC … and couldn’t find the correct folder path. I looked all through the Vista folder structure, which only served to frustrate me. On XP, the directory path was something like C:\Documents and Settings\%user%\Local Applications\Application Data\. In Vista C:\Documents and Settings\%user%\ has been replaced with simply C:\Users\%user%\.
But I couldn’t find anything there like what I needed, nor anywhere else for that matter, so I wrote a quick little Console application to output the Special Folder path. Sure enough, it turns out to be C:\Users\%user%\AppData\Local. I went back to Windows Explorer and could not see the folder. Of course, that is when I realized that the folder was hidden.
No problem, I thought, I just need to alter the view to show hidden files and folders, something I’ve done a hundred times on Windows machines. So I right-click in the folder, select “Customize This Folder”, and … nothing. No option to show hidden items. Hmmm, they must have moved it. I right-click and try “Properties”. Still no joy.
Finally, in the tool bar, under the “Organize” drop down, I find an option for “Folder and Search Options”. This window has a “View” tab that reveals the old View options I am used to seeing. Finally! I checked the option for “Show hidden files and folders” (and made a couple of other changes while I was in there) and now I can finally find the correct path. I hate relearning old tricks.
So back to the lesson: I found the correct path, which had been created by my application, retrieved the binary file from the Network store, and replaced the new one created by the application install. I open the application and Viola! – all my boss’s configurations are happily restored.
So, take advantage of the Special Folder system. The folder structures between XP and Vista are quite different, but using this approach made reinstalling my old .NET 1.1 application a happy affair.
Developing For .NET is a year old!
Well, it’s official: today marks the first anniversary of the first post here at developingfor.net.? One year ago today, a friend and former co-worker Jim Burnett wrote the first post about ini File Access with VB.NET.? Jim only wrote a few other posts before moving on to other projects, but he got the ball rolling.
Over the last year, there have been 53 posts, almost 7,000 unique visitors, and over 11,000 page views.? The average view numbers steadily climb every month.? Several of the posts are even frequently submitted to Digg.? What this tells me is that some readers out there like the site and are getting something out of it.? That was always the goal: to help others.
What I would like is to hear from you, the reader.? I’d like to know what you like, what you don’t like, and what you’d like to see.? Send requests for topics, samples, or code that you would like to see here on the site.
So thanks for making 2007 a great start: register today and post a comment, help me make this site even better in 2008.
— Joel Cochran
New Vista Machine follow up
I let VS2008 finish installing last night while I was at home. I got in this morning, and the system had done an automatic update. It loaded a ton of updates from Microsoft, some were Vista specific but most were not. I was able to confirm that VS2008 installed just fine and I have spent the rest of the morning installing other software.
My experience today has been much different than yesterday. Everything seems to be sailing along: I’ve installed a number of applications, configured some network connections, a printer, installed FireFox and extensions, and did some other configuration. All in all I have nothing to complain about: it seems the Windows Update did a lot of good for this machine.
I’ll probably spend the rest of the day setting up some other goodies, and at lunch time I am picking up my new 22″ Widescreen LCD monitor. After that, I have some SPROC development to do. I promise I’ll be getting to LINQ soon.
New ThinkPad T61 with Vista Business
My new laptop arrived today. I’ve been playing with it for a few hours now and thought I would share my initial reactions with you.
This is a Core Duo 2.2Ghz processor with 3GB of RAM. It has a 15.4″ widescreen LCD display, which is gorgeous. My favorite feature so far is the integrated fingerprint reader: logging in is super easy and secure. But software installation is shocklingly slow. It only took an hour or so to get the initial Vista install configured, but everything after that has been less than optimum.
I was so excited by my new machine that I went to Staples at lunch time and picked up a new Logitech wireless mouse and keyboard. I bought a docking station with this laptop for the office, one goal of which is to switch back to a regular mouse, keyboard, and monitor. The keyboard part is largely to restore my hands, which hurt quite a bit after working day in and day out on a laptop keyboard. Of course, I know I could have used a regular keyboard with my old laptop, but I found that it pushed the screen to far away. With the new display, that is not an issue. I’m also hoping to use both the built in LCD and an external 22″ widescreen monitor, which should give me loads of space for Visual Studio and related tools. Anyway, I connected my new mouse and keyboard (I haven’t bought the monitor yet) via the USB connector and they worked immediately. I did not even need to push the device “Connect” buttons.
After that, it was time to start installing software. First, I tried to install IBM’s iSeries Access for Windows, V5R4. This was the first task for the CD drive, and it sounded like a rocket ship taking off. It got about half way through the install, whirring, buzzing, and scraping all the while, and then it just quit. I tried to bring up Task Maanger, but it would not show itself. Finally, I popped the disc out and reset it. I don’t think I had it seated all the way although it seemed fine. I resumed the setup and the noises were gone. At the end of setup, I received a “Updating software, please wait” message that never went away. Eventually, I succeeded in bringing up the Task Manager and the process showed running but 0% CPU. I ended it, thinking the install failed, but it appears to have worked.
I closed Task Manager, but in my shortcut tray there were now 2 task manager icons that would not go away, and clicking on either did not reactivate the Task Manager. Sigh. I decided a reboot was in order.
Except the machine would not reboot. I tried restart, log off, and shut down. I tried them from the Start menu and from Task Manager. Each responded to the mouse click yet accomplished nothing. Finally, I did the old push and hold the power button technique to get the machine to shut off. When I brought it back up, I received no errors or warnings about a previous incorrect shutdown.
While it was coming back up, I hit the Google Highway and found that this is a fairly typical problem: the USB devices connected to the machine were preventing it from shutting down. Now, the only two devices connected are my printer and the Mouse and Keyboard connector mentioned above. According to the complaints I found on the web, the Mouse was most likely the culprit and the solution was to update the drivers. Now, I’ve used Logitech accessories for about 7 years, and I’ve never been a fan of their software. I just want a stinking mouse and keyboard that work, I don’t need to use them to program my dishwasher. The last few times I’ve installed their products I have been able to forego installing their software, but this time I figured I’d better do it if I want to be able to shut down my machine, so I did.
The good news is that installing “Logitech SetPoint 3.3a” seems to have solved the problem. After the install I was able to restart from the Start menu just fine. The bad news was that it took almost 15 minutes to install.
I have a stack of other software to install, including of course our erstwhile Visual Studio 2008 and Expression Blend Preview 2. I’ll let you know how these go as well.
Update:
Xara Xtreme, an awesome (and inexpensive) vector based graphics tool installed no problem and took less than 5 minutes.
New problem: I can’t get to the Network. It appears that Norton Internet Security, which came preloaded and is active on this machine, is preventing me from seeing my network. I’m investigating this problem now, but I can’t get on with the installs until I can get to the network path where they are stored.
Update 2:
OK, annoying, but I basically had to disable the Norton Personal Firewall, at which point the network location I was seeking became visible. I established a connection and the system offered to remember the password, which I said yes to. Then, the Fingerprint reader asked me to verify who I was with a swipe of a digit. Way cool! Anyway, it’s off to VS2008 next.
Update 3:
New problem: I am using Microsoft’s Virtual CDRom Control Panel to mount the VS2008 ISO files to a local drive. When I execute the program, it denies access to the needed files. I found in Vista you can right-click and Run the application as Administrator, which worked. I was able to install the driver and mount the file to a local drive letter. The problem now is that the Computer window will not show or find the mounted drive letter. I guess I’ll either need a different emulator or to try and find a Vista update for Virtual CDRom.
Update 4:
OK, I found a freeware utility called Virtual CloneDrive that appears to work on Vista.? I was able to install it and mount the ISO file to a drive.? Immediately, the Autorun.exe started (which never worked on Virtual CDRom XP for me) and I began installing VS2008.? It is 3.5 GB (after I removed C++ and Crystal Reports), so it might be a while.? I’m going to let it run and head home.? I’ll check in tomorrow.
Live Blogging RVNUG – December 2007
Tonight I am visiting RVNUG (Roanoke Valley Dot Net Users Group) for the first time. Kathleen Dollard, a columnist for Visual Studio Magazine and author of Code Generation in Microsoft .NET (which I have and have read most of) is the featured presenter. She will be discussing “Refactoring with Generics”. How to make your code better with Generics, using Framework Generics, and how to use and make your own Generics.
Here are some bullets I garnered from the presentation:
- Find out about the Converter<T> Generic Delegate.
- “Team Test” is now part of VS2008.
- Anonymous Delegates employ “Closure” – allows a private variable to be trucked off to (captured by) an out of scope method (like an anonymous delegate)
- Return a LINQ list immediately by using “.ToList()”: no deferred execution
- Format for declaring my own generics and specifying Type inheritance: public class GenericClass<TData, TCollection> : SomeBase where TCollection : List<TData> where TData : class
Conclusions
Overall, a good presentation. Unfortunately, it is a little dated when you consider all the new technologies out there. Kathleen did include some optional approaches using LINQ and Lambdas, but the bulk of the material is still 2.0 based. Don’t get me wrong: I’m not saying I didn’t learn anything because I did. I think I have a much better handle on creating my own generic classes now. But I think the target audience for this presentation should be developers moving from 1.1 to 2.0 or new developers.
Now for the scary part: the topic is very relevant. There are still an incredible number of people developing in pre-2.0 technologies who need this kind of information.
Kathleen is great: if you ever get a chance to go to a presentation of hers, by all means treat yourself: she really knows her stuff. We had a nice talk during dinner about the future of LINQ to SQL, OR/M, the Entity Data Model, and other Framework issues.? She was very patient with my questions and her answers reveal that she is one smart cookie.
Upgrade your C# Skills part 3 – Lambda Expressions
I’ve been very busy continuing my C# 3.0 and .NET 3.5 self-education. I’ve been focusing primarily on LINQ, but before I cover that here, which will take several postings, I wanted to cover Lambda Expressions. If you have been reading about LINQ and its related technologies at all, you’ve surely come across this term already. If you’ve already read some about Lambdas, then perhaps you came to the same conclusion I did: a lot of writers covering Lambda Expressions seem to want you to be boggled by them. In most articles, I found myself wading through a bunch of stuff I really did not need to know. In fact, it sometimes simply added more confusion.
So my goal in this article is to bypass all the pocket protector stuff and get right down to brass tacks. Here are a list of things I will NOT be covering that pervade almost every other article about Lambda Expressions:
- Lambda calculus
- Anonymous Methods
- Functional Languages
- Lexical Closures
If you are interested in any of the above, they are plenty of other articles out there. If, however, you are like me and just want to use this stuff, then read on…
Anonymous Methods
Before you scream foul, yes, I said I wasn’t going to discuss these, and really, I’m not. Or more accurately, I’m not going to explain them or show examples. You do have to know that Lambda Expressions are just another way to write Anonymous Methods. *whew*! Glad we got that out of the way!
The tricky part, though, for many programmers is knowing when to use Anonymous Methods. As far as our discussions go, it will be pretty easy: you want to use Anonymous Methods whenever you need to pass a method reference. This is done by use of delegates, something else I’m not really going to talk about.
So what you need to know is this: where ever you see a method that requires a delegate (or a reference to a method), you can use a Lambda Expression instead. An Anonymous Method is just a way to write the code for such a delegated method inline. So, we just need a way to know when we can use Lambda Expressions.
Actions, Predicates, and Funcs
What we need are Delegate Types. Delegate types are declared signatures for method calls that are used to wrap instance methods or, in our case, anonymous methods. Fortunately for us, there are some Generic Delegate Types built in to .NET that we can put to good use.
Action<T>
This is a Generic Delegate defined in .NET that will wrap and execute a method, passing it a variable of type T. Here is the MSDN Documentation. If you use this in a method declaration, you can actually pass a reference to a method, anonymous or otherwise, to a method of your own creation. For an example, check out this Extension Method:
public static void ExecuteOnValues<K, V>(this IDictionary<K, V> sequence, Action<V> action) { if (sequence == null) { throw new ArgumentNullException("sequence"); } foreach (var item in sequence.Values) { action(item); } }
You can see here that our method signature expects a Generic Action<T> method reference. What we don’t know is what this method will do. The code line action(item) is saying “execute the method passed in on my action parameter, and pass it the item as a parameter.” So our Action method receives the Value of our Dictionary as a parameter and does something with it. We are going to use Lambda Expressions to define the “something”. Here is a simple example:
var dict = new Dictionary<int, string>(); dict.Add(1, "Coding"); dict.Add(2, "in"); dict.Add(3, "C#"); dict.Add(4, "Rules!"); dict.ExecuteOnValues(f => Console.WriteLine(f.ToString()));
Here we have created a new Dictionary<TKey, TValue> collection and added some data. Because Dictionary<TKey, TValue> inherits from IDictionary<TKey, TValue>, we can use our new Extension Method to execute some code against all the values in our Dictionary. But remember that our Extension Method really has no executing logic: it is expecting us to send it a reference or a delegate to it so it knows what to do. Enter the Lambda Expression. In the ExecuteOnValues method call above, f => Console.WriteLine(f.ToString()) is a Lambda Expression.
Anatomy of a Lambda Expression
// A simple Lambda expression f => Console.WriteLine(f.ToString())
The “=>” thingy in the middle is the Lambda operator. This is what lets you know a Lambda is what is happening here. Let’s break the rest down into two parts: the left side and the right side. The left side represents a parameter list to be passed into the method. The right side represents the code the method will execute. Really, that’s it. You can make it harder if you want, but ultimately this is all it boils down to. Here is a diagram:
// A simple Lambda expression f => Console.WriteLine(f.ToString()) PARM Lambda CODE TO EXEUTE
So you can think of this as a method defined like so:
// A faux method representing a Lambda void Method (unknownType f) { Console.WriteLine(f.ToString()); }
In essence, without getting into all the pocket-protector details, this is what is the compiler is doing for you when it sees a Lambda Expression. The above is psuedo-code, and not entirely accurate, but you get the idea.
Where this gets confusing is that you really don’t see any type declarations, either for the parms or the return value. This is more Compiler Inference at work. In our example above, we specified that our Action generic was based on the Value Type of the Dictionary. The Compiler is able to look at the context of the Lambda Expression and simply infer that f is whatever type we specified on the Action parameter. You could write the details out, specifying the types, but not needing to is one of the major draws of Lambdas: the code is more compact and it “just works”. Now we’ll change our Dictionary to have a different Value type. We’ll make it our standard Person and add some people to it:
var dict2 = new Dictionary<int, Person>() { {1, new Person() {FirstName = "John", LastName = "Smith", Age = 32, DOB = "12/31/1988"}}, {2, new Person() {FirstName = "Jimmy", LastName = "Crackcorn", Age = 57, DOB = "08/08/1934"}}, {3, new Person() {FirstName = "Mary", LastName = "Contrary", Age = 44, DOB = "09/10/2000"}} }; dict2.ExecuteOnValues(f => Console.WriteLine("{0} is a {1} born on {2}", f, f.GetType().Name, f.DOB));
Now if we run this we’ll get these results (Click for full size image):
And now we get to see something else: in this Lambda, I am executing methods and Properties on my parameters. Pretty cool, huh?
So let’s read this Lambda out loud: “GIVEN f, EXECUTE {Console..WriteLine(“{0} is a {1} born on {2}”, f, f.GetType().Name, f.DOB));}”
Confused about the Looping? Don’t be: the loop is actually happening back in our Extension Method. All that’s happening here is that this code is executing (inside the loop) and using each Value from our Dictionary as the GIVEN parameter.
Predicate<T>
This is a Generic Delegate that evaluates a condition and returns true or false. Notice that Action<T> did not return any values. Predicate<T> is different because it returns a boolean value, and ultimately its only purpose is to determine whether or not a certain condition is met. Here is the MSDN documentation.
Let’s create a custom PersonCollection class and add a method that returns a sublist of Person objects who meet an unspecified criteria:
class PersonCollection : List<Person> { public List<Person> MatchingPersons(Predicate<Person> condition) { List<Person> list = new List<Person>(); foreach (Person p in this) { if (condition(p)) { list.Add(p); } } return list; } }
This code is specific to our PersonCollection class but still takes advantage of Predicate<T> to filter itself into a subsetted list. Let’s execute this now and get back just a list of Veterans:
var people = new PersonCollection() {new Person() {FirstName = "John", LastName = "Smith", Age = 32, DOB = "12/31/1988", IsMilitaryVeteran=true}, new Person() {FirstName = "Jimmy", LastName = "Crackcorn", Age = 57, DOB = "08/08/1934", IsMilitaryVeteran=false}, new Person() {FirstName = "Mary", LastName = "Contrary", Age = 44, DOB = "09/10/2000", IsMilitaryVeteran=true}}; Console.WriteLine("Print them all:"); people.ForEach<person>(f => Console.WriteLine("{0} is a {1} born on {2}", f, f.GetType().Name, f.DOB)); Console.WriteLine(); // Get a subset of people var veterans = people.MatchingPersons(f => f.IsMilitaryVeteran); Console.WriteLine("Print just veterans:"); veterans.ForEach<person>(f => Console.WriteLine("{0} is a {1} born on {2}", f, f.GetType().Name, f.DOB));
The beauty here is we did not specify what the criteria for the filtering was: we could have just as easily asked it for all the people whose first names begin with the letter “J”:
// Get another subset of FirstName beginning with "J" var js = people.MatchingPersons(f => f.FirstName.StartsWith("J")); Console.WriteLine("Print just Js:"); js.ForEach<person>(f => Console.WriteLine("{0} is a {1} born on {2}", f, f.GetType().Name, f.DOB));
Here is a screen shot of running all three of these in a row (Click for full size image):
Personally, I think this is a great tool, and the Lambda Expressions just make it that much more readable and easy to develop.
Func<T>
So far, we’ve seen Generic Delegates that return void and bool. That’s nice, and we can do a lot with them, but sometimes you need something more. This is where FUNC<T> comes in to play: it can return any type. In this case, the T is the return type. In the MSDN Documentation, they use “TResult” instead of “T”, so I’ll do that too. There are five Func Generic Delegates defined in .NET 3.5:
- Func<TResult> – no parameters, returns type TResult
- Func<T, TResult> – 1 parameter, returns type TResult
- Func<T1, T2, TResult> – 2 parameters, returns type TResult
- Func<T1, T2, T3, TResult> – 3 parameters, returns type TResult (are you noticing a pattern yet?)
- Func<T1, T2, T3, T4, TResult> – 4 parameters, returns type TResult
What’s cool about Func is that you can create your own methods on the fly and give them meaningful names. Here is a simple example:
// Get a subset of people using Func Func<Person, bool> isVeteranBeginsWithJ = f => f.IsMilitaryVeteran && f.FirstName.StartsWith("J"); Console.WriteLine("Print just veterans whose first name's begin with \"J\":"); foreach (Person p in people) { if (isVeteranBeginsWithJ(p)) { Console.WriteLine("{0} is a {1} born on {2}", p, p.GetType().Name, p.DOB); } }
As you can see, I simply use my Func as any other method. I can see where this would come in very handy for short term reusability. Also, a lot of LINQ elements require Func delegates, so you have to have it in your toolkit.
Some odds and ends
There are a few items that I have to mention. First of all, Action<T> also has a few multiple parameter options:
- Action<T1, T2>
- Action<T1, T2, T3>
- Action<T1, T2, T3, T4>
We did not discuss sending multiple parameters to a Lambda. To do so, wrap them in parentheses, like so:
// Example from Microsoft (x, y) => x == y
While Compiler Inference is at work here, it is not required. If you wish to specify types for readability you can:
// Example from Microsoft (int x, int y) => x == y
Calling a Lambda with no parameters, such as Func<TResult> is done with empty parentheses:
Func<string> getSomething = () => "Something"; Console.WriteLine(getSomething());
Lambdas can access local variables:
string todo = "To Do"; Func<string> getSomethingTodo = () => "Something " + todo; Console.WriteLine(getSomethingTodo());
And Lambdas can be just as complex as you want them to be. Here is a Lambda that receives our custom PersonCollection and calculates the average age based on the DOB (if you’ve looked at the initializers, you’ll find that the Ages and the DOBs do not balance):
Func<PersonCollection, int> calculateAverageAge = (PersonCollection c) => { int totalAges = 0; foreach(var p in c) { string[] parts = p.DOB.Split(new char[] { '/' }); int year = int.Parse(parts[2]); int calcAge = DateTime.Now.Year - year; totalAges += calcAge; } int averageAge = totalAges / people.Count; return averageAge; }; Console.WriteLine("Average Age of collection is {0}", calculateAverageAge(people));
And lots more. This is hardly the definitive article on Lambdas, but hopefully it explains enough to get you started. There is certainly enough background here to begin using Lambdas with LINQ, which will be next in this series of articles. Here is a link to the MSDN Lambda Expressions (C# Programming Guide).