Delegates
Pointer to a function.A way to pass methods the same way you pass values and objects around
delegate int DiscountDelegate();Just like a class, however, it isn't very useful until we create an instance of it.
Remember that a delegate is nothing more then a reference to a method.
Even though DiscountDelegate does not have any constructors, when creating one, there is an implicit constructor that wants a method matching its signature (no params, returning int).
Type in the name in the same way you would call the method; all you do is omit the parentheses.
Another way to think of a delegate is that it defers the execution of a method.
}
Func
Later, in 3.5, they were nice enough to give us some common delegates to use so we wouldn't have to constantly define our own. They expanded Action and added Func, and the only difference between them is that Func matches methods that return a value and Action matches ones that do not.This means that we do not need to declare our DiscountDelegate and instead can use Func
Our delegate's signature now becomes Func
class Program { static void Main(string[] args) { new ShoppingCart().Process(new FuncType inference allows us to completely omit the explicit creation of Func(Calculator.Calculate)); } } class Calculator { public static int Calculate(bool special) { int discount = 0; if (DateTime.Now.Hour < 12) { discount = 5; } else if (DateTime.Now.Hour < 20) { discount = 10; } else if (special) { discount = 20; } else { discount = 15; } return discount; } } class ShoppingCart { public void Process(Func discount) { int magicDiscount = discount(false); int magicDiscount2 = discount(true); } }
eliminating the need to even explicitly create a Func delegate
// works because Process expects a method that takes a bool and returns int new ShoppingCart().Process(Calculator.Calculate);
Anonymous methods
Anonymous methods let you declare a method body without giving it a name.Anonymous methods can only be created when using delegates and, in fact, they are created using the delegate keyword.
new ShoppingCart().Process( new Func(delegate(bool x) { return x ? 10 : 5; } ));
You can put as much or as little logic between the curly braces as you would in any other method.
there is even more trimming we can do. Naturally, we can omit the need to explicitly declare the Func delegate; .NET takes care of that for us when we use the delegate keyword.
new ShoppingCart().Process( delegate(bool x) { return x ? 10 : 5; } );
The true power of anonymous methods can be seen when using .NET methods that expect delegates as parameters and when responding to events. Previously, you had to create a method for every possible action you wanted to take. Now you can just create them inline and avoid polluting your namespace.
// creates an anonymous comparer custs.Sort(delegate(Customer c1, Customer c2) { return Comparer.Default.Compare(c1.ID, c2.ID); }); // creates an anonymous event handler button1.Click += delegate(object o, EventArgs e) { MessageBox.Show("Click!"); };
Lambda expressions
From MSDN: 'A lambda expression is an anonymous function that can contain expressions and statements, and can be used to create delegates or expression tree types.'lambda expressions replace anonymous methods and add many features.
Looking back at our last example, we had trimmed the code down to where we were basically creating the entire discount algorithm in a single line.
new ShoppingCart().Process( new Func(delegate(bool x) { return x ? 10 : 5; } ));
Lambda expressions use the 'goes to' operator => to indicate what parameters are being passed to the expression.
The compiler takes this a step further, and allows us to omit the types and infers them for us.
If you have two or more parameters, you need to use parentheses: (x,y) =>. If you only have one, however, you don’t need them: x =>.
static void Main(string[] args) { Funcdel = x => x ? 10 : 5; new ShoppingCart().Process(del); } // even shorter... static void Main(string[] args) { new ShoppingCart().Process(x => x ? 10 : 5); }
Yep, that's it. The boolean type of x is inferred and so is the return type, because Process takes a Func
static void Main(string[] args) { new ShoppingCart().Process( x => { int discount = 0; if (DateTime.Now.Hour < 12) { discount = 5; } else if (DateTime.Now.Hour < 20) { discount = 10; } else if(x) { discount = 20; } else { discount = 15; } return discount; }); }
One last thing…
There is an important difference between using braces and not using them. When you use them, you are creating a 'statement lambda', otherwise it is 'expression lambda'. Statement lambdas can execute multiple statements (hence the need for braces) and can not create expression trees. You will probably only run into this problem when working with the IQueryable interface. The example below shows the problem.Statement Lambda use curly braces and can execute multiple statements (hence the need for braces) and can not create expression trees.
ListThe second assignment of bar fails at compile time. This is because IQueryable.First expects an expression as a parameter whereas the extension method Listlist = new List (); IQueryable query = list.AsQueryable(); list.Add("one"); list.Add("two"); list.Add("three"); string foo = list.First(x => x.EndsWith("o")); string bar = query.First(x => x.EndsWith("o")); // foo and bar are now both 'two' as expected foo = list.First(x => { return x.EndsWith("e"); }); //no error bar = query.First(x => { return x.EndsWith("e"); }); //error bar = query.First((Func )(x => { return x.EndsWith("e"); })); //no error
It's hard to end the discussion here, but I feel I must. Lambdas are basically broken into two categories; the kind that create anonymous methods and delegates, and the kind that create expressions. Expressions are an article by themselves and are not necessarily required knowledge to be a .NET developer (although their implementation in LINQ certainly is).
Informative graphic showing different parts of LINQ query
my thanks to:
http://www.codeproject.com/Articles/47887/C-Delegates-Anonymous-Methods-and-Lambda-Expressio
http://www.codeproject.com/Articles/19154/Understanding-LINQ-C
0 comments:
Post a Comment