New Language Features
So earlier this afternoon I delivered a talk about new language features in .NET 3.5 for Singapore audiences. I admit it's not the best talk I've ever done, even worse, it's not even good.
For you guys who didn't grab the concept or wanted to know more, below is the long explanation about how things should've gone through...
First of all, I've created a small console application, to display the result of the code. I can type all code but no result, that's uninteresting. So for the talk, I've created a search application. I have not emphasized this basic functionality of the application during the talk. A search application is the easiest form of querying a collection of data, so it should be very natural.
Up next is the "source query" we are going to use throughout the talk. Previously the talk was designed for this query to be put at the final conclusion, where all of the features combined. This time, I tried a different way.
The "source query" is then translated to "ordinary function calls".
Note to self: the appearance of Lambda expression there is quite confusing. I should use anonymous method or standard delegate next time (to ease the transition from 2.0).
To make sure that both syntax behave exactly the same, we're going to switch to demo mode to see it in action.
Here's the code for "source query":
return
from cookie in christmasCookies
where cookie.Name.Contains(lookup)
select cookie;
And here's the code for "ordinary function calls":
return
christmasCookies
.Where(cookie => cookie.Contains(lookup))
.Select(cookie => cookie);
If you run it, both will return same result. I can open it using Reflector to see similar code for both function.
Now that you know the syntax equivalence of the "source query", we can move on to discuss each language features that is used to make LINQ actually works...
The first and most visible is Extension Method. The methods called in the "ordinary function calls" are one-to-one replacement with LINQ keywords; where for .Where(), select for .Select(), etc.
Extension method enables you to add method to an existing class without limitation of the class' inheritance modifier. You can add method to an abstract, sealed, normal, or even interface.
To illustrate the usage, I've created a simple extension method for speech synthesis. It also outlines the ease of use of .NET TTS engine.
Here's the code:
static class SpeakExtensions
{
public static void Speak(this string str)
{
System.Speech.Synthesis.SpeechSynthesizer synth = new System.Speech.Synthesis.SpeechSynthesizer();
synth.Speak(str);
}
}
Now you can make any string to .Speak() by calling the extension method. Take note that you are not subclassing or recompiling the System.String class.
Advanced note: under the hood, extension method uses a concept of static class/method to do it's magic (that's why it has to be declared inside a static class). Static class and static method are basically available to be called from any part of the code (provided you referenced them). Now if one of this method takes an instance of an object and do something to it, you can achieve the extension method behavior. But, using this path will make your code very messy (lots of static calls). Extension method hides (not removes) all the mess under a very elegant syntax.
Next huge part is Lambda Expression. This part is almost one-to-one replacement with "source query", because this part encapsulates the logic of the query. On the slide we have two logic, the first one is selection logic, and the second one is output logic.
Lambda expression relieves you from having to define the parameter types and the rigid structure of delegate instantiation. It is actually 100% exchangeable with anonymous delegate or standard delegate.
To illustrate this, I have created a code of how lambda have evolved from delegates.
Here is the "standard delegate way":
foreach (int i in wholeNumbers.FindAll(EvenNumber))
Console.WriteLine(i.ToString());
...
private static bool EvenNumber(int input)
{
return (input % 2 == 0) ? true : false;
}
Note that you need to define the named delegates first before you can use them in the .FindAll function.
And here's the "anonymous delegate way":
foreach (int i in wholeNumbers.FindAll(delegate(int input) { return (input % 2 == 0) ? true : false;}))
Console.WriteLine(i.ToString());
Note that you still need to pass in parameter types (v2.0 is already smart enough to infer the output parameter type).'
And here's the newly invented lambda expression:
foreach (int i in wholeNumbers.FindAll(input => (input % 2 == 0) ? true : false))
Console.WriteLine(i.ToString());
Note that there are no delegate declaration or parameter type setting.
Then come the shortcut trio; Object Initializer, Collection Initializer, and Auto-Implemented Property. All three can be easily recognized as syntactic sugar (well, almost all of the new features are syntactic sugar -- it runs on top of v2.0 CLR!).
These features simplify object declaration and instantiation. The first two are easy to understand, auto-implemented property also very simple.
Note to self: I should've written a small program on the fly for the demo. No need to prepare anything. Create classes with auto-prop, and then instantiate it using both initializer, and then output the result to screen.
Then come the confusing part, Anonymous Types. It's easy to use this in query, but it's not easy to create a real-world application for this.
Anonymous types enables you to have a strong typed class/type, without the need to declare any of the property, or even better, without the need to declare it.
The question I have not been able to answer is, in real world, when do you need to use anonymous types. In a real world scenario where all business entities are perfectly defined, I don't see any usage of anonymous types. Note that, this feature can be great if you're prototyping some application or creating some object on the fly (and still keep the strong type).
Opening the DLL using Reflector is one way to make sure that the classes are generated on compile-time rather than run-time (thus, keeping the strong typing).
Note to self: think hard on creating a good scenario for this feature demo.
The final one is Type Inference. I predict that this will be the mostly used feature since it is both convenient and safe to use.
Type inference relieves developer from the need to specify a type to a field on declaration. The type is inferred from the first assignment. The field is neither variant (can be of any type) nor System.Object (which will need boxing-unboxing process when used).
To illustrate this, I create a simple code below:
var inferredField = 1;
inferredField = "One";
You will not be able to compile the above code since the compiler will infer and declare the field type to System.Int32 (the first assignment). If you're trying to assign a string literal to an integer field, you will get compiler error.
But wait, there's another feature? Yes, and it is called XML Literal. Should the previous speaker (name hidden) does not spoil this, it would be the big closure of the day. (hey, no offense man, we didn't sync up on this one :D)
Note: I didn't even bother to put anyting in the slide because of the suspense it creates.
XML Literal enables Visual Basic developer (yes, you read that right -- this is a VB-specific feature!) to copy and paste an XML file into the code as an XML (not string). Not also that, you can also output an XML using this feature. So you can write XML inside your VB code using some XML Literal, some LINQ to XML, and some plain old function call. It sounds mixed up, but it does the job. (And that is what VB does -- the job.)
To illustrate the usage, I created an XML reader in place of the collection initializer:
Dim xmlCookies = _
<ChristmasCookies>
<Cookies>
<Id>88653C79-2F49-40fd-9BBD-38EE0B5C69CA</Id>
<Name>Chocolate Mint Cookies</Name>
...
Return _
From cookie In xmlCookies...<Cookies> _
Select New With { _
.Id = New Guid(cookie.<Id>.Value), _
.Name = cookie.<Name>.Value
}
Neat!
In Summary, here we have the list of new features I have explained. Just in case someone missed the name of the feature.
Note to self: should tell a little summary about each feature (forgot to do this earlier).
And comes the standard blurb slide. Shameless self-promotion and contact methods.
Done!
(P.S.: In case you didn't notice, you can click on each slide picture to get a bigger view of it)