• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 130
  • Last Modified:

How can I learn to understand this crazy syntax? Enumerable.OrderBy<TSource, TKey> Method (IEnumerable<TSource>, Func<TSource, TKey>)

Hi,
I'm looking at this https://msdn.microsoft.com/en-us/library/bb534966(v=vs.110).aspx
The syntax and how it translates to coding is baffling for me.  Is this Linq sytanx?  Any suggestion that I can understand what it mean with
Enumerable.OrderBy<TSource, TKey> Method (IEnumerable<TSource>, Func<TSource, TKey>)

Thank you.
0
lapucca
Asked:
lapucca
  • 3
  • 3
  • 2
  • +1
1 Solution
 
Paul MacDonaldDirector, Information SystemsCommented:
You can't, which is why Microsoft pushes it so hard.  Stick with VB.Net like the rest of us.  C# has no advantage.
0
 
lapuccaAuthor Commented:
Lol...  Too late for that advice for me.  I'm a C# developer but haven't done so for about 4 years and now having problem understanding these new syntax.
0
 
Paul MacDonaldDirector, Information SystemsCommented:
FWIW, you've picked one of the more convoluted examples.  

C# has always seemed backwards to me, and every time we consider converting from VB we look at some of the really difficult stuff we've done and decided we would never pull it off in C#.
0
Cloud Class® Course: CompTIA Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

 
Kyle AbrahamsSenior .Net DeveloperCommented:
Also note that this is for lambda expression, and it's a lot easier if you see them in practice.

Take some

List<Class> myList;

myList.OrderBy( c => c.FirstProperty).ThenBy( c=> c.SecondProperty);

One advantage to C# . . . it does make use of int Pointers which VB has still not yet done.  They're 99.9% the same - and you never need it until that one esoteric situation when you realized you're really boned without it.  I've taken it upon myself to keep in touch with both languages, this way I can work for a job that uses either.
0
 
käµfm³d 👽Commented:
Highly opinionated response, I see...   ; )

Disregarding the above, what you have is a mix of generics and extension methods. You know its an extension method because the first parameter to the method has the this modifier. Extension methods just give you fancy syntactic sugar. They are nothing more than static methods. The sugar they provide is that you can have an instance of an IEnumerable, say a List<string>:

List<string> someList = new List<string>();

and you can have a new method called OrderBy that isn't really attached to the List class, but for which you can call the method using member notation (i.e. dot notation):

IEnumerable<string> result = someList.OrderBy(...);

Here, the OrderBy isn't a member of List. If you go to definition of the List class, you won't see one mention of the OrderBy method. The syntactic sugar of extension methods gives us the appearance of a member method.

Extension methods are ways to provide a kind of template for a class that can really apply to multiple kinds of things. Take the List class that I used above. You'd agree that I can have lists of all kinds of things, right? For example:

Lists of strings
Lists of apples
Lists of cars

Well, the logic of a list is pretty much the same for each of those. So should it be in code. I can create a template class called List that deals with different kinds of types:

public class List<T>
{
    private T[] items;

    public List<T>(int maxItems)
    {
        this.items = new T[maxItems];
    }
}

Open in new window


So I've created a skeleton for the logic. Within the skeleton I've added a placeholder variable for any types that I might deal in. Using what I mentioned previously:

List<string> listOfStrings = new List<string>(10);
List<Apple> listOfApples = new List<Apple>(45);
List<Car> listOfCar = new List<Car>(2);

Under the hood, .NET actually creates new classes that represent each of the types. With a generic, the type is the name and angle brackets:

List<string>
List<Apple>
List<Car>

So three new types were created by the runtime using my skeleton as a template.

As for the OrderBy method itself, it's a generic method--you know this because of the angle brackets, and it's an extension method--you know this because of the use of this. So OrderBy can work on many different types because it is an extension method, and it can be called like a member function because it is an extension method.

Now let's examine the individual parameters:

this IEnumerable<TSource> source
Func<TSource, TKey> keySelector

The first parameter is decorated with this. This usage implies that you should be calling this method against some object that is IEnumerable of some type (TSource). (I used "T" in my skeleton above. Here, MS is using "TSource". It doesn't matter what you use. The name is just a placeholder. Just be sure to use it throughout wherever you think that type needs to be placed.) If I had a List<string>, then I could order it by each item:

IEnumerable<string> orderAscending = listOfStrings.OrderBy(item => item);

I'll get to the arrow (=>) bit shortly. I have to capture the result because the OrderBy is not "in-place". It will not modify the list itself; only return a result.

Now, the second parameter says Func<blah blah>. Func is a delegate. A delegate, I hear you wondering, is just an object that wraps up a function. You can basically treat a function as if it itself were a piece of data. You can pass this delegate around to other methods, and those methods can cause the method being wrapped to be executed. For instance, I might create a method:

private string GetGreeting()
{
    return "Hello World!";
}

Bland, but we don't need anything exciting here. I can create a new Func instance that wraps this method:

Func<string> greetingWrapper = new Func<string>(GetGreeting);

Take note of two things:

* See those angle brackets? That means Func is generic.
* Notice how when I refer to GetGreeting I don't use any parentheses after it? Weird, huh? That's because adding the parentheses would cause the the method to be executed. I don't want to do that. I only want to make reference to it, hence no parentheses.

Now I can use this delegate in another method:

void PrintGreeting(Func<string> greetingWrapper)
{
    Console.WriteLine(greetingWrapper());    // Here I do use parentheses because I actually do want to execute the method that the delegate wraps.
}

And I call it as:

static void main()
{
    Func<string> greetingWrapper = new Func<string>(GetGreeting);

    PrintGreeting(greetingWrapper);
}

private string GetGreeting()
{
    return "Hello World!";
}

Open in new window


I'll grant you that this contrived example doesn't look very meaningful. But take into account the OrderBy. It's 2nd parameter expects a Func. That means you can alter what the OrderBy orders by just by altering what the Func points to. If you have a complex object with multiple properties, say:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

You can order by first name:

string OrderByFirstName(Person p)
{
    return p.FirstName;
}

...or by last name:

string OrderByLasstName(Person p)
{
    return p.LastName;
}

...just by passing the delegate:

Func<string, string> byFirstNameFunc = new Func<string, string>(OrderByFirstName);
Func<string, string> byLastNameFunc = new Func<string, string>(OrderByLastName);

var byFirstName = listOfPeople.OrderBy(byFirstNameFunc );
var byLastName = listOfPeople.OrderBy(byLastNameFunc );

C# (and VB.NET) also have lambda syntax, which is the arrow I demonstrated earlier. I'll save you the techical details, but know that a shortcut for doing the above, without having to actually declare two methods named "OrderByFirstName" and "OrderByLastName" would be:

var byFirstName = listOfPeople.OrderBy(p => p.FirstName);
var byLastName = listOfPeople.OrderBy(p => p.LastName);
0
 
käµfm³d 👽Commented:
P.S.

FWIW, I find VB.NET's lambda syntax to be much more of a pain in the butt than C#'s.

e.g.

Dim byFirstName = listOfPeople.OrderBy(Function (p) p.FirstName)

It's even worse when you get into multi-line lambdas  ; )
0
 
lapuccaAuthor Commented:
Kyle,
I get myList.OrderBy( c => c.FirstProperty).ThenBy( c=> c.SecondProperty); and the example at the link.  My problem is I just don't know how to intrepret that syntax they provided and convert that to code.  
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
      this IEnumerable<TSource> source,
      Func<TSource, TKey> keySelector
)

Thank you
0
 
käµfm³d 👽Commented:
P.P.S.

The convention that MS uses for Func and its overloads is that the last type parameter (the thing(s) inside the angle brackets) is the return type, and everything else is the type of a parameter, in left-to-right-order. So a Func<string> should wrap a method that takes no parameters and returns a string; a Func<string, int> should wrap a method that has one parameter or type string and which returns an int; a Func<byte, string, char> should wrap a method that has two parameters, the first being type byte, the second being type string, and which returns a char; etc.
0
 
lapuccaAuthor Commented:
Kaufmed,
LOL...  I'm glad you're taking side with C#.  Thank you for the wonderful explanation.  I'm still digesting all of it.
0
 
Kyle AbrahamsSenior .Net DeveloperCommented:
Kaufmed elegant explanation.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Amazon Web Services - Basic

Are you thinking about creating an Amazon Web Services account for your business? Not sure where to start? In this course you’ll get an overview of the history of AWS and take a tour of their user interface.

  • 3
  • 3
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now