Don't normally bother writing blogs that just reference another blog, but this one gem me a while to find, so if only for my own reference I'm copying it here:
Original entry was here, nice one :)
Software Development with .Net
Don't normally bother writing blogs that just reference another blog, but this one gem me a while to find, so if only for my own reference I'm copying it here:
Original entry was here, nice one :)
Following on from the previous post about old assemblies being updated with the latest .Net 3.5 service pack, I thought it also worth mentioning the other gotcha that can happen when targeting old versions of .Net from VS2008.
If you have a project that is set to target .Net 2.0, VS will dutifully only allow you to add 2.0 assemblies to the project, ensuring that you don't accidentally make use of 3.0 or 3.5 framework features that perhaps aren't installed on the machines of your target audience. However, VS will still use the latest compiler to compile the code, hence you can make use of 3.0 language features such as var, lambdas etc. These work, even on a box with just the 2.0 framework installed, because they are all handled via compiler magic - there was no change to the resulting IL to support the new 3.0 language features.
Now this can either be a good or a bad thing. Good, because you can start making use of the new language tools without requiring your customer to upgrade anything. Why bad? Three reasons I can think of:
What can you do? Well, if you're in the "it's a good thing" camp, then just get coding. If the bad things are important to you, then the bad news is that there's not much you can do on your development machines to help (other than go back to VS2005!). What you can do is to ensure that on your CI build machines you specify the TargetFramework option to MSBuild. This forces MSBuild to use the appropriate versions of the compiler and other tools. See this blog for more details. That way, if a dev uses some 3.0 language feature, it will cause the CI build to fail and hence get spotted nice and quickly. You don't have a CI server? Shame on you.
There have been a number of posts about the changes introduced in .Net 3.5 SP1, but this is one I've not seen before. I'm not sure that the title, "breaking changes" is entirely correct, but it probably got your attention :)
In .Net 3.0, there was a new class, System.Collections.ObjectModel.ObservableCollection<T> (I'm sure you can guess what it does). It had two constructors, ObservableCollection<T>() and ObservableCollection<T>(List<T>). Clearly the guy who wrote it was having a bad day - List<T> as a constructor parameter? What's all that about?
This stayed the same in .Net 3.5, but changed with .Net 3.5 SP1. Now, ObservableCollection<T> has an additional constructor, ObservableCollection<T>(IEnumerable<T>) - i.e., the one that they should have had in the first place instead of List<T>. All is good in the world.
Now there's a nice feature in VS2008 whereby you can indicate in the project properties which version of .Net you are building for. This means that VS makes sane choices as to which assemblies you can reference, meaning that the code you write should run just fine on a machine that's only got old versions of the framework, even if you've got all the latest spanky stuff installed. (There's another issue to do with the compiler, but I'll cover that in another blog).
Here's the problem. If you have .Net 3.5 SP1 installed, and you create a project that targets 3.0, VS will happily only add 3.0 references. Including the reference to the assembly (WindowsBase, if you care) that contains ObservableCollection<T>. Which SP1 upgraded. So you can write code that takes advantage of the new constructor, such as:
ObservableCollection<int> x = new ObservableCollection<int>(new int[] { 1, 2 });
which will compile and run just fine.
When you finally complete all your coding and have all your tests passing, you pass it to your customer confident in the knowledge that you've done a good job. He installs and runs the code, and the very first impression he gets of your work is a MethodNotFound exception, since you're calling a constructor that he doesn't have on his machine.
So what do you do? There's not much you can do on your development system, other than be careful, which isn't much help. What you can, and should, do is to make sure that your build server and test environments exactly match the minimum that you expect your code to be running on. That way, a problem like the one above will get spotted during the development process where it can be easily fixed. Note that it's probably a good idea to turn off automatic updates on build & test machines, otherwise you'll probably end up getting stuff pushed down that you didn't want.
[Update]
Just found out that FxCop has a rule to detect and warn on the usage of such methods - see Brad Abrams blog posting on the subject here. That helps no end :)