Reflections on Tech-Ed 2007 - Part 5
This is the last post in the series on the Tech-Ed 2007 highlights, covering the remaining two technical sessions.
DEV313 – LINQ Deep Dive
While the title of this session implies an exclusive coverage of LINQ (Language Integrated Query) being introduced in C# 3.0 [338kB DOC] (part of .NET 3.5), the session itself provided much more value by covering pretty much all of the other new language features in C# 3.0. The presenter, Alex James, cleverly snuck in these language features by showing how the LINQ syntax evolved from a .NET 2.0 implementation of a data query with generics (the C# equivalent of C++ templates).
Here are the new language features introduced along the way:
- Extension Methods. By adding the 'this' keyword to a method parameter (preferably the first), the method can be called as if it belonged to the class of that parameter. For example, with an extension method:
public static IEnumerable<Tgt; Where(this IEnumerable<T> source, Predicate<T> filter) {...}
the function can be called on 'source':
return sampleSource(sampleFilter);
as well as in the traditional way:
return DataUtils.Where(sampleSource, sampleFilter);
Thus the extension method appears to be part of IEnumerable<T>. This helps similar calls to be chained instead of nested. - Lambda Expressions. This provides a short-hand notation for defining anonymous delegates. For example, given a delegate defined as:
public delegate bool Predicate<T>(T t);
an instance of this delegate can be defined as:
Predicate<GPFunction> chainableFilter = fn => fn.NumOfChildren > 1 && fn.ReturnType == fn.ChildSpec[0].ReturnType;
instead of:
Predicate<GPFunction> chainableFilter = new delegate(GPFunction fn) { return (fn.NumOfChildren > 1 && fn.ReturnType == fn.ChildSpec[0].ReturnType); }
* If anyone is wondering what GPFunction, etc. is all about, feel free to read my Computer Science for Honours thesis [910kB PDF] on Genetic Programming. - Implicit Typing. This introduces the var keyword, which is used just like in JavaScript. While it may seem strange to introduce late binding of data types when strong typing is already present, it becomes very helpful when anonymous types are used (explained next). Once a type has been bound, that variable cannot be assigned a new type.
- Anonymous Types. This is a logical extension of anonymous delegates, applied to data types in general. It allows declaration of lightweight data structures (i.e. tuples) without having to specify a full class or struct:
var dataItem = new {Name = "ClassName", Type = DataTypes.String}; var duplicateItem = new {Name = dataItem.Name, Type = dataItem.Type};
In the evolution of LINQ example, anonymous types were used in the definition of the Where extension method, considering that the programmer can select any number of properties in any order (as in SQL).
The last step was ‘adding a bit of syntactic sugar’, which transformed this long chain of method calls into SQL-like syntax. It also illustrated why the ‘select’ clause is at the end of the LINQ expression, as opposed to the beginning as in SQL. The select clause simply filters the fields to be included in the anonymous type collection returned by the expression, though the first thing that needs to be defined is the data source. This is specified in the ‘from’ clause.
One final note: LINQ can be implemented over anything that implements IEnumerable<T>, though in situations where a small subset of the data is returned, the performance can be rather inefficient. To improve performance, objects would have to implement the IQueryable<T> interface. This basically allows the filter to be applied first before ‘hydrating’ the selected records into memory, instead of retrieving all records before filtering them.
CON206 – Custom Activities in Windows Workflow Foundation
This was the last session on Day 1, so naturally one would be feeling tired after all the earlier sessions. Keeping this in mind, it was helpful that the presenter, Matthew Winkler, exhibited such energy and enthusiasm in his presentation that there was little chance of falling asleep!
The session itself covered so much, from the basics of workflows to using workflows in multithreaded applications, that it was a fast-paced sprint through all the concepts with demos thrown in. I really appreciate how Matthew maintained a consistent pace so that nothing was skipped out, nor did the session go overtime. Of course, it does take a bit of time for these concepts to sink in, so it was great that the slides have been made available on the website.
In simplest terms, a workflow is a set of activities in some arrangement, such as a state chart or basic flow diagram. The activities are the fundamental unit of work and may be composited into higher-level activities. Each activity has an associated execution state, which follows the state machine shown below:
Workflow Foundation state transitions
In this diagram, the green arrows represent transitions initiated by the workflow runtime, and all other arrows represent transitions initiated by the activity. Blue arrows represent final transitions, and red arrows represent faults triggered from within the activity.
In practical terms, all activities inherit from System.Workflow.ComponentModel.Activity and therefore must implement the following virtual methods (note the American spelling):
- void Initialize(IServiceProvider provider)
- ActivityExecutionStatus Execute(ActivityExecutionContext context)
- ActivityExecutionStatus HandleFault(ActivityExecutionContext context)
- ActivityExecutionStatus Cancel(ActivityExecutionContext context)
Additionally, an activity may implement the ICompensatable interface to 'compensate' activities that have finished and succeeded. Thus, in order to be compensated, an activity must be in the Closed state and have an ExecutionResult of "Succeeded". Probably an easy way to understand compensation of activities is to think of rolling back transactions when an operation has already completed, but some business requirement has not been met. When this happens, an exception is typically thrown and the runtime invokes the compensation handler of the activity. This means that the activity must also implement the following method:
- ActivityExecutionStatus Compensate (ActivityExecutionContext context)
I have to admit that I haven't actually played with Workflow Foundation yet, so there's obviously much more implementation detail in terms of putting everything together. The best place to start is with the samples, though it's good to have that essential high-level knowledge in order to understand why things are done the way they are.
Final thoughts
So Tech-Ed has well and truly finished for another year. It has been a great experience for me, and I learned quite a lot of useful information from it. I have to admit it has been hard to pass this knowledge on - especially when having to summarise parts of it in ten seconds or thereabouts and somehow convey it to a mass audience (i.e. my work colleagues). I could simply direct them to this blog for reference, but it looks like I'd need to deliver the knowledge in a mentoring session to be effective. Hopefully some of my colleagues are already reading this and getting something out of it!