Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Help understanding some C# code

Tags:

c#

Can someone please explain to me the following method? I don't quite understand what it does, and how it does it.

private List<Label> CreateLabels(params string[] names)
{
    return new List<Label>(names.Select(x => new Label { ID = 0, Name = x }));
}
like image 406
learning Avatar asked Aug 10 '10 06:08

learning


2 Answers

Let's separate it into different bits:

private List<Label> CreateLabels(params string[] names)

This means we're declaring a method returning a list of Label references. We're taking an array of string references as a parameters, and it's declared as a parameter array which means callers can just specify the arguments like this:

List<Label> labels = CreateLabels("first", "second", "third");

(Or they can explicitly pass in an array of strings as normal.)

Now to understand the body, we'll split it up like this:

IEnumerable<Labael> labels = names.Select(x => new Label { ID = 0, Name = x });
List<Label> list = new List<Label>(labels);
return list;

The second and third lines should be fairly simple - it's just constructing a List<Label> from a sequence of labels, and then returning it. The first line is likely to be the one causing problems.

Select is an extension method on the generic IEnumerable<T> type (a sequence of elements of type T) which lazily returns a new sequence by executing a projection in the form of a delegate.

In this case, the delegate is specified with a lambda expression like this:

x => new Label { ID = 0, Name = x }

That says, "Given x, create a Label and set its ID property to 0, and its Name property to x." Here the type of x is inferred to be string because we're calling Select on a string array. This isn't just using a lambda expression, but also an object initializer expression. The new Label { ID = 0, Name = x } part is equivalent to:

Label tmp = new Label();
tmp.ID = 0;
tmp.Name = x;
Label result = tmp;

We could have written a separate method to do this:

private static Label CreateLabel(string x)
{
    Label tmp = new Label();
    tmp.ID = 0;
    tmp.Name = x;
    return tmp;
}

and then called:

IEnumerable<Label> labels = names.Select(CreateLabel);

That's effectively what the compiler's doing for you behind the scenes.

So the projection creates a sequence of labels with the names given by the parameter. The code then creates a list of labels from that sequence, and returns it.

Note that it would (IMO) be more idiomatic LINQ to have written:

return names.Select(x => new Label { ID = 0, Name = x }).ToList();

rather than explicitly creating the List<Label>.

like image 117
Jon Skeet Avatar answered Sep 25 '22 01:09

Jon Skeet


In general, the meaning behind well written code can often be deduced by the code itself. This is called "self-documenting code." Code that doesn't follow this, should hopefully be accompanied by comments.

In this case, here is how you could figure out what the code does:

The method gives you some key bits of information:

  • The name of the method. This lets you know what the method does. In this example, the method is called CreateLabels

  • The method's signature. This indicates what the method requires. In this example, there is an array of type string, with the keyword params. The keyword params indicates that this method will accept one or more names as inputs to the method, and will collect them into a single array.

  • The method's return type. This will tell you want the method will give you when it's finished. In this example, it returns a List of Labels.

So, since the method is called CreateLabels, takes an series of string called names, and returns a list of lables, we might say that "Given several names, this method will return a list of lables"

Now if you need to know how the method is doing this, then have a look at the body.

return new List<Label>(names.Select(x => new Label { ID = 0, Name = x }));

For someone who does not understand linq or lambda expressions, this is a bit difficult to understand.

Lets work our way from outside to inside:

return new List<Label>() constructs a new list and returns the new list, and causes the method to exit.

names.Select() Is a method that will apply a set of operations to all the objects in the array, and return a new collection which will contain the result of applying those operations.

x=>new Label {ID = 0, Name = x} is a lambda expression that says: x goes to a new Label object who's ID field is 0, and Name is the value of x.

Putting it all together, the statement return new List<Label>(names.Select(x => new Label { ID = 0, Name = x })); is creating a new Label Object for each name in names and stores it into a new list, which is returned at the end of the method.

It is a way of also writing:

List<Labels> toReturn = new List<Labels>();
foreach(string name in names)
{
 Label l = new Label();
 l.ID = 0;
 l.Name = name;
 toReturn.Add(l);
}
return toReturn;
like image 29
Alan Avatar answered Sep 24 '22 01:09

Alan