|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Services
Chapters
Feature Zones
|
IntroductionLambda expression is an inline delegate introduced with C # 3.0 language. It’s a concise way to represent an anonymous method. It provides a syntax to create and invoke functions. Although Lambda expressions are simpler to use than anonymous methods, they do slightly differ on how they are implemented. Both anonymous methods and Lambda expressions allow you define the method implementation inline, however, an anonymous method explicitly requires you to define the parameter types and the return type for a method. Lambda expression uses the type inference feature of C# 3.0 which allows the compiler to infer the type of the variable based on the context. Lambda expression can be broken down into parameters followed by execution code. e.g.: Parameter => executioncode.
The left hand side represents zero or more parameters followed by the lambda symbol Lambda expression allows us to pass functions as arguments to a method call. I will start with a simple example of lambda expression which returns even numbers from a list of integers. //simple example of lambda expression.
public static void SimpleLambdExpression()
{
List<int> numbers = new List<int>{1,2,3,4,5,6,7};
var evens = numbers.FindAll(n => n % 2 == 0);
var evens2 = numbers.FindAll((int n) => { return n % 2 == 0; });
ObjectDumper.Write(evens);
ObjectDumper.Write(evens2);
}
Looking at the first lambda expression assigned to the Another place where parentheses are required in lambda expressions is when you want to use a parameter in multiple blocks of code inside the lambda expression such as follows: delegate void WriteMultipleStatements(int i);
public static void MultipleStatementsInLamdas()
{
WriteMultipleStatements write = i =>
{
Console.WriteLine("Number " + i.ToString());
Console.WriteLine("Number " + i.ToString());
};
write(1);
}
In the above code sample, we have enclosed our code in curly brackets so that we can use the parameter in both the expressions. If there were no curly brackets, the compiler wouldn't be able to recognize the variable You can use lambda expressions where a delegate may not have any parameter. In that case, you have to supply a pair of empty parentheses to signify a method with no parameter. Here is a simple example which illustrates a lambda with no parameter. delegate void LambdasNoParams();
public static void LambdasWithNoParameter()
{
LambdasNoParams noparams = () => Console.WriteLine("hello");
noparams();
}
C# 3.0 defines the number of generic delegates that you can assign to your lambda expression instead of public static void GenericDelegates()
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7 };
Func<int, bool> where = n => n < 6;
Func<int, int> select = n => n;
Func<int, string> orderby = n => n % 2 == 0 ? "even" : "odd";
var nums = numbers.Where(where).OrderBy(orderby).Select(select);
ObjectDumper.Write(nums);
}
In the above example, we are using three different extension methods: Func<int, bool, string, double, decimal> test;
If your method or There are cases where type inference may not return the data type that you really want the lambda expression to return. In those cases, we can explicitly specify the parameter type on the lambda expression. For example: Func<double, int> expr = (x) => x / 2;
The above expression returns a compiler error because by dividing a Func<double, int> expr = (x) => (int)x / 2;
Lambda expressions are basically of two types. One is considered a simple expression where everything is inferred and consists of an expression only. The second type of lambda expression is statement blocks which are composed of braces and return type. Let's write a lambda expression in both forms to see the difference: //example showing two types of lambda expressions
public static void ExplicitParametersInLambdaExpression()
{
Func<int, int> square = x => x * x;
Func<int, int> square1 = (x) => { return x * x; };
Expression<Func<int, int>> squareexpr = x => x * x;
Expression<Func<int, int>> square2 = (int x) => { return x * x; };//does not compile.
}
Let's go ahead and dissect each lambda expression one at a time. The first lambda expression is considered a simple expression which does not have a statement body because there is no return statement and braces whereas the second lambda statement includes a statement body because it has a return statement and braces. Although both get compiled to a delegate, the benefit of lambda expressions without a statement body is that it can be converted to an expression tree which a certain provider can use to generate its own implementation. This is much like LINQ to SQL will convert the expression tree to its domain specific language called SQL, and send it to the database. The third lambda expression is really where lambda expression shies from an anonymous method. The beauty of this statement is the fact that you can easily convert to an expression whereas anonymous methods can only be converted to Func<int,int> sq = squareexpr.Compile();
The last lambda expression raises an exception because the compiler cannot convert a lambda expression that contains a statement body, as you can observe from the fact that it is surrounded by braces and a return statement. Although you can use lambda expressions to generate expression trees, there is nothing preventing you from directly creating your own expression tree. Let’s walk through an example of creating an expression tree for a lambda expression //example creates expression tree of x *x
public static void CreatingExpressionTree()
{
ParameterExpression parameter1 = Expression.Parameter(typeof(int), "x");
BinaryExpression multiply = Expression.Multiply(parameter1, parameter1);
Expression<Func<int, int>> square = Expression.Lambda<Func<int, int>>(
multiply, parameter1);
Func<int, int> lambda = square.Compile();
Console.WriteLine(lambda(5));
}
You first start off with a parameter expression of type ParameterExpression parameter1 = Expression.Parameter(typeof(int), "x");
The next step is to build the body of lambda expressions which happens to be a binary expression. The body consists of a multiply operator to the same parameter expression. BinaryExpression multiply = Expression.Multiply(parameter1, parameter1);
The final step is to build the lambda expression which combines the body with the parameter as follows: Expression<Func<int, int>> square = Expression.Lambda<Func<int, int>>(multiply,
parameter1);
The last step converts the expression to Func<int, int> lambda = square.Compile();
Console.WriteLine(lambda(5));
Creating An Expression from Another ExpressionYou can take an expression tree and modify it to create another expression from it. In the following example, we will start off with a lambda expression of public static void CreatingAnExpressionFromAnotherExpression()
{
Expression<Func<int, int>> square = x => x * x;
BinaryExpression squareplus2 = Expression.Add(square.Body,
Expression.Constant(2));
Expression<Func<int, int>> expr = Expression.Lambda<Func<int, int>>(squareplus2,
square.Parameters);
Func<int, int> compile = expr.Compile();
Console.WriteLine(compile(10));
}
We start off with a lambda expression which returns a Expression<Func<int, int>> square = x => x * x;
Next we generate the body of the new lambda expression by using the body of the first lambda expression and adding a constant of BinaryExpression squareplus2 = Expression.Add(square.Body, Expression.Constant(2));
In the last step, we generate the new lambda expression by combining the body with the parameters from the first lambda expression. The important point which I discovered in the statement below is that, a parameter's reference needs to be exactly the same from the first lambda expression which is Expression<Func<int, int>> expr = Expression.Lambda<Func<int, int>>(squareplus2,
square.Parameters);
Closures and Lambda ExpressionsClosure is a concept that comes from functional programming. It essentially captures or uses the variable which is outside the scope of the lambda expression. What it essentially means is you can use variables inside the lambda expression that are declared outside the scope of the lambda expression — you are able to use and capture the variable that is outside the scope of the lambda expression. This has its advantages but could lead to issues as well since the outside context has the ability to change the variable value. Let’s drill through an example of lambda expression in the context of closure. public static void LambdaWithClosure()
{
int mulitplyby = 2;
Func<int, int> operation = x => x * mulitplyby;
Console.WriteLine(operation(2));
}
In the above example, we are using the There are certain restrictions when you are using a lambda expression with a parameter with delegate void OutParameter(out int i);
delegate void RefParameter(ref int i);
public static void GotchasWithLambdas()
{
//example with out parameter int i;
OutParameter something = (out int x) => x = 5;
something(out i);
Console.WriteLine(i);
//example with ref parameter.
int a = 2;
RefParameter test = (ref int x) => x++;
test(ref a);
Console.WriteLine(a);
}
Notice in the above code, I am explicitly specifying the parameter type of Another restriction that I have come across using lambdas is you cannot use the delegate void ParmsParameter(params int[] ints);
public static void LambdaWithParam()
{
ParmsParameter par = (params int[] ints) =>
{
foreach (int i in ints)
{
Console.WriteLine(i);
}
};
}
SummaryIn this article I introduced the syntax of a lambda expression — how it replaces anonymous methods. We also talked about how lambda expressions differ from anonymous methods because of the type inference, and its ability to be easily transformed into delegates or expression trees. We learned the parameter restrictions of lambda expressions and how to write an expression from scratch and compile it to a delegate and vice versa. History
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||