.NET 4.0 and C# 4.0
Version 4.0 of C# now supports support for late binding, type equivalence support, and Covariance and Contravariance. The type equivalence support is pretty important because it allows you to embed another assembly's types right in your own assembly so that you can reference those types without having to reference the other assembly at runtime. Why is that a good thing? Because that way you can link at runtime to different versions of that other assembly, which in the past has been very difficult.
The fourth version of the .NET framework itself also brings a lot of improvements. For example, there's a new class called Tuple that can greatly simplify your life if you're accustomed to languages like Python. Here's an example line of C# code:
var primes = Tuple.Create(2, 3, 5, 7, 11, 13, 17, 19);
This isn't quite as elegant as tuples in languages such as Python where you can just do this:
primes = (2, 3, 5, 7, 11, 13, 17, 19)
The difference, of course, is that in Python tuples are built right into the language. In C#, you're using a .NET class called Tuple. And indeed the Tuple class only supports up to eight items in its constructor, as that's how many overloads the constructor has. But you can add more items to the Tuple after you've created it. (But that, of course, goes against the tuple concept in other languages such as Python where they're supposed to be immutable. But that's OK. Different languages, different rules.)
I was surprised to see memory-mapped files included in the list of new features. Memory-mapped files are something we Win32 programmers from days of old used to use both for managing large amounts of virtual memory and for creating our own customized file formats. (If you're not familiar with memory-mapped files, think of them as similar to the memory swap files, except instead of being managed by the operating system, they're separate files managed by your application.) Technically, you could always use memory-mapped files in .NET by calling directly into the Win32 API. But now there's a .NET class, called MemoryMappedFile, specifically for them.
If you have experience in older C/C++ languages, you know what a welcome relief the .NET IO classes were, especially the File, Directory and Path classes. For some reason, traversing files and subdirectories had always been a pain in the rear. I remember fighting with the God-forsaken file-searching routines in C, and their abysmal Win32 API equivalents. Microsoft certainly simplified these activities with the .NET classes (as did the creators of other languages such as Python). And now in .NET they're even easier. The newest version of the Directory class includes methods that return enumerations. That means you can use LINQ on them.
In terms of architecture, there are a lot of improvements to .NET. For example, there's an entire set of classes now for supporting multicore, parallel programming and even LINQ. (This might look familiar. That's because it is. Microsoft released an early version of these classes called .NET Parallel Extensions, and they ran under .NET 3.5. I took these classes for a spin and they're really great. For example, there's a Parallel.For method that functions very much like a traditional for loop, except the code inside the loop runs in parallel for each iteration rather than sequentially. Indeed, using some tracing tools, by creating a parallel for loop with many iterations, I was able to see that they were being distributed among the cores of my CPU. Very cool.
There are lots of small, miscellaneous improvements to .NET as well. Several additional classes now support a Parse and TryParse method like we already have in Int32 and others. (Examples include Enum, which will come in handy, and Guid, which may occasionally be useful.) There's a new generic collection class called SortedSet (which technically speaking in mathematical terms is an oxymoron, but you get the idea).