Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confused about LINQ parameters

Tags:

c#

linq

I am trying to understand LINQ and become confident at using it. What I am struggling with are the parameters asked for. Example:

var sortedWords = words.OrderBy(a=>a.Length)

words is an array collection. OrderBy's intellisense says:

Func<string, TKey> keyselector

A func executes a method, and a string is the value, TKey a key.

In the example http://msdn.microsoft.com/en-us/vcsharp/aa336756.aspx#thenBySimple (ThenBy - Comparer), we compare length by saying a => a.Length. I understand that syntax, but how is that related to what the intellisense is asking for?

I tend to find the method signature and intellisense unreadable because of all the generics.

Thanks.

like image 221
GurdeepS Avatar asked Mar 10 '09 23:03

GurdeepS


2 Answers

The type (as displayed by Intellisense) makes sense if you understand the nature of lambda expressions in .NET/C#. Otherwise, it can indeed seem a bit strange to the newcomer. Begin by considering that the type of keySelector, Func<TSource, TKey> is simply a delegate. Before C# 3.0, you would call such a method by passing a delegate as a parameter, for example:

IEnumerable<string> sortedWords = words.OrderBy(new Func<string, int>(mySelectorMethod));

where mySelectorMethod is the name of an ordinary method which takes a string as a parameter and returns an int. (As a side point, I suppose you could use anonymous delegates, but let's not go there for now.) Also, note that this example is purely illustrative, as LINQ is almost always used with .NET 3.5/C# 3.0 (though I believe it can be used with either/both .NET 2.0/C# 2.0 - someone correct me if I'm wrong). Since C# 3.0, methods can be defined inline as lambda expressions, which are intended to be used in precisely such circumstances as these. Read over the MSDN article on lambda expressions (linked above) if you want to get a proper introduction, but here I will simply describe the use in this specific context. As you state, your code (in C# 3.0) is something like the following:

var sortedWords = words.OrderBy(a => a.Length);

The part of the expression that is a => a.Length is the lambda expression, which is really just shorthand for declaring a function inline. The syntax of lambda expressions is quite simple for the most part; to the left of the => the arguments are specified, generally in the form (arg1, arg2, arg3), but since there's only one in this case you can omit the brackets. To the right of the => is the expression that is the return value of the function (lambda expression more accurately). Alternatively you can enclose actual code with a return statement within { and } though this is usually unnecessary. What I believe the C# compiler does is recognises the parameter passed to OrderBy as a lambda expression and then compiles it into a function and creates and passes the delegate for you. Note that lambda expressions can also be converted to System.Linq.Expressions.Expression objects (accessible expression trees) instead of delegates, but this is a much less common usage. Anyway, there's a lot going on behind the scenes here, but hopefully this should at least clarify why the type is Func<TSource, TKey> and how it relates to the lambda expression. As I said, read up on MSDN if you want a deeper understanding of LINQ/lambdas/delegates...

like image 58
Noldorin Avatar answered Oct 06 '22 01:10

Noldorin


a => a.Length

I understand that syntax, but how is that related to what the intellisense is asking for?

This chunk of code is a lambda expression. A lambda expression is a handy way of generating an Anonymous method (in this case), or a System.Linq.Expressions.Expression . Let's break it down by parts.

  • The most noticeable feature is the =>, which seperates parameters from a method body.
  • On the left side of the =>, there is a symbol: a. This is the declaration of a parameter for our anonymous method. The compiler is aware that we are calling OrderBy(), and that OrderBy requires a Func<string, object>. The parameter for such a function is a string, so the compiler determines that a must be a string. The only thing the programmer needed to provide is a name.
  • On the right side of the =>, there is method body. Since this is a one-liner, the return keyword is implied. The IDE provides intellisense against a as a string, which allows you to use the Length property.

Now, consider this C# 2.0 ...

IEnumerable<string> sortedWords = 
  Enumerable.OrderBy(words, delegate(string a) {return a.Length;});

With the C# 3.0

IEnumerable<string> sortedWords = words
  .OrderBy(a => a.Length);
like image 23
Amy B Avatar answered Oct 06 '22 02:10

Amy B