When generics and yield were introduced in the C# 2.0 spec, I was quite impressed, but not as impressed I am from the C# 3 spec (pointed out on the Nemerle blog via Monologue). I can’t wait to use these features.
Here’s an overview of what’s getting a lot better.
In C# today, I find myself using this pattern over and over again:
SomeType[] elements = (SomeType[])elemArrayList.ToArray(typeof(SomeType))
With generics, I haven’t tried this, but I think at least we get to simplify it as:
SomeType[] elements = elemArrayList.ToArray()
That’s not bad. One repetition gone. With C# 3.0, we get to eliminate all repetition with implicitly typed local variables:
var elements = elemArrayList.ToArray()
I have wanted extension methods for so long. Extension methods let you add instance methods to types that you don’t have control over. That is, let’s say you want to implement the Merge Sort algorithm over ArrayLists. Today, you’d have to do this in a separate class and call it as:
MyAlgos.MergeSort(myArrayList).
Not so bad. In C# 3.0, you declare MergeSort as an extension method by adding the this keyword in the parameters:
void MergeSort(this ArrayList list) { … }
That makes it available to be called simply as:
myArrayList.MergeSort().
Oooooo.
In C# 2.0 we got anonymous methods/delegates. I haven’t used them, but apparently you can simplify:
void Print(object x) { Console.WriteLine(x); }
MyFunc(mylist, new MyFuncHandler(Print));
as
MyFunc(mylist, new MyFuncHandler(object x) { Console.WriteLine(x); } );
Or something like that. Still a bit too verbose for me. With C# 3.0, we get lambda expressions, which are tightened-up anonymous methods.
MyFunc(mylist, (x) => { Console.WriteLine(x); } );
Much nicer.
Next, we get object initializers, which are interesting… It’s a bit like the With statement in VisualBasic. If you have a regular Point class with properties X and Y, you now get to simplify creating a point from:
new Point(10, 20)
to
new Point { X = 10; Y = 20; }
Hmmm.
Object initializers are probably just there to support another more interesting (not really) new feature: anonymous types. The scenario where I think these could be most helpful is when you have a function that returns two or more things. An example off the top of my head is, say, a function that returns two factors of a number, e.g. for 10 it returns 2 and 5 (2*5=10), for 21 it returns 3 and 7 (3*7=21). Currently, we have two options. The first is to use out parameter:
void GetFactors(double val, out double firstFactor, out double secondFactor) { … }
The second option is to create a new data type for the return value:
struct GetFactorsReturn { public double FirstFactor, SecondFactor; }
GetFactorsReturn GetFactors(double val) {
…
GetFactorsReturn retval = new GetFactorsReturn();
retval.FirstFactor = …;
retval.SecondFactor = …;
return retval;
}
In C# 3, we can simplify this second option by not having to define the new data structure explicitly. Forget the struct GetFactorsReturn definition, and the return from GetFactors looks like:
return new { FirstFactor = …; SecondFactor = … }
There’s a problem, though. The name of this anonymous type is generated by the compiler and is not accessible from code, so we can’t declare methods that use this type as a parameter or return value. So our GetFactors function could only be declared as:
object GetFactors(double val) { … }
Also note that anonymous types are always reference types inheriting from Object. If we could reference these types in method signatures somehow, and if we could choose whether they should be value or reference types, this would be much more helpful.
We get some more sugar in the form of collection initializers and implicitly typed arrays:
var myList = new List { 0, 1, 2, 3 };
var myArray = new[] { 0, 1, 2, 3 };
Lastly there are query expressions, which look like a way to use an SQL-like syntax to filter collections of objects. I’m not so sure this is really needed in the language, but it’s a whole new thing that needs to be looked at more closely.