Lambda expressions are used in place of anonymous methods and delegates. They are used extensively in the LINQ namespace and other enumerated data types for their readability of condition matching.
Refer to the ArrayExtensions.cs
and FuncExtensions.cs
file in the ExtensionMethods.Library
project for the extension methods. These methods are used in the Program.cs
file in the ExtensionMethods.Console
project.
The following code snippet shows an overloaded extension method ToList()
which accepts a mapping function as a lambda expression:
public static class ArrayExtensions { /// <summary> /// Converts an array of items to List<T> using a mapping function /// </summary> /// <typeparam name="T"></typeparam> /// <param name="items"></param> /// <param name="mapFunction"></param> /// <remarks>Taken from http://www.extensionmethod.net/csharp/array/tolist-t-func-object-t-func</remarks> /// <returns></returns> public static List<T> ToList<T>(this Array items, Func<object, T> mapFunction) { if (items == null || mapFunction == null) return new List<T>(); List<T> coll = new List<T>(); for (int i = 0; i < items.Length; i++) { T val = mapFunction(items.GetValue(i)); if (val != null) coll.Add(val); } return coll; } }
The following code is another extension method that focuses on extending a lambda expression or function to memorize the execution if the data is the same:
public static class FuncExtensions { /// <summary> /// Memoize a function /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="TResult"></typeparam> /// <param name="func">the function to memoize</param> /// <remarks>http://www.extensionmethod.net/csharp/func/memoize-t-tresult</remarks> /// <returns></returns> public static Func<T, TResult> Memoize<T, TResult>(this Func<T, TResult> func) { var t = new Dictionary<T, TResult>(); return n => { if (t.ContainsKey(n)) return t[n]; else { var result = func(n); t.Add(n, result); return result; } }; } }
The following code shows the use of the extension methods:
private static void DoTaskEleven() { Func<string, string> format = new Func<string, string>(s => { // a long running operation System.Threading.Thread.Sleep(2000); return String.Format("hello {0}", s); }).Memoize(); // takes 2000 ms for (int a = 0; a < 100;a++ ) { System.Console.WriteLine(format(" world")); } } private static void DoTaskElevenPart2() { User[] users = new User[] { new User { FirstName = "Shawn", LastName = "Mclean" }, new User { FirstName = "Derron", LastName = "Brown" } }; var userVMs = users.ToList<UserViewModel>(o => { var item = (User) o; return new UserViewModel { FullName = (item).GetFullName(), UserId = item.UserId }; }); }
The first code snippet, ToList()
, is an extension of the array object which takes a mapping lambda expression function as a parameter. This function is then used to convert the values of the array to the type specified in the template definition. When calling this extension method, we simply apply the class type to the template and pass in the expression as a parameter as seen in the DoTaskElevenPart2()
method in the use cases code snippet
users.ToList<UserViewModel>(o => ...
The second code snippet, Memoize()
, is an extension to the Func
type. This is an extension method that does not incorporate lambda expressions as parameters but actually extends it. This use case is rare because there are usually better design patterns to use to accomplish the solution. In this method, we Memoize
the value passed to the expression to prevent further processing, if it has already been called with that same data before.
The DoTaskEleven()
snippet shows the body of the expression containing a sleep
function that should take 2 seconds to execute. When Memoize
is attached, if the method was already executed before with the same parameters, the body will never get executed again and the return value is returned from the cache, a dictionary in this case.
In this recipe, you have learned how to use lambda expressions to help make your extensions more flexible and also how to extend an actual lambda expression.