Thursday, March 7, 2013

The evolution of delegates and anonymous methods

A delegate is a type that safely encapsulates a method, see MSDN for a deep-dive.
I want to concentrate on showing how delegates evolved during the versions of the .NET Framework.

Let's look at .NET Framework 1.0 first:
A delegate declaration looks like this:

 public delegate double NetWageCalculation(Employee emp);  


Next, you need a method with a signature that is corresponding to the delegate declaration:

 public double GetTaxReducedWage(Employee emp)  
 {  
   return emp.GrossWage * 0.8;  
 }  


Delegates are classes (derived from System.MulticastDelegate), so they can be instantiated:

 NetWageCalculation calc = new NetWageCalculation(GetTaxReducedWage);  


With .NET Framework 2.0 the C# compiler shipped with a feature called "delegate inference". That gives you the possibility to omit the instantiation with "new". Because you mention the delegate once ("NetWageCalculation calc = ..."), the compiler automatically recognizes that you want to new up a delegate:

 NetWageCalculation calc = new NetWageCalculation(GetTaxReducedWage);  


Moreover, this version of the Framework supported anonymous methods. With anonymous methods the amount of code that had to be written for instantiation of delegates was reduced because no separate methods had to be coded any more:

 NetWageCalculation calc3 = delegate(Employee emp) { return emp.GrossWage * 0.8; };  


The next step in evolution of delegates were lambda expressions introduced in .NET Framework 3.5. Lambdas are simplifying anonymous methods:

 NetWageCalculation calc3 = delegate(Employee emp) => { return emp.GrossWage * 0.8; };  


Examining closely, we will realize that there is still a lot of "ceremony" in the the code snipped above. Two features allow further simplification:
"Delegate type inference" gives you the possibility to omit the types of parameters ("Employee" in that case) - the compiler automatically detects the types of the passed parameters.
"Return type inference" gives you the possibility to omit the return statement.

 NetWageCalculation calc3 = (Employee emp) => { return emp.GrossWage * 0.8; };  

Again without disturbing strike-throughs:

 NetWageCalculation calc3 = emp => emp.GrossWage * 0.8;  






No comments:

Post a Comment