Linq implicity typed range variable

With Linq, a range (e) variable can be implicitly entered from the array / collection (emps) it comes from, but the foreach statement cannot do the same without the var keyword or type. Why is this?

In ex1, the compiler knows that e is of type Employee, without specifying the var keyword or anything else. Why the foreach loop in ex2 cannot do the same, you must specify a type (be it var or some type).

EX1.

Employee[] emps = {new Employee ( 1, "Daniel", "Cooley", 7, 57.98M }; public void SortByLastname() { var sortedByLastname = from e in emps orderby e.LastName select e.FirstName; } 

ex2.

  foreach (Employee empl in emps) { Console.WriteLine("Employee " + empl); } 

It may be an analysis, but I'm trying to understand why this is so.

The answer may be very good, because the Linq query syntax is configured to automatically display the type of a range variable, but the foreach status is not. Can someone explain why this is?

+7
source share
4 answers

The reason you don't need to specify this type is because it breaks down (mostly) extension methods. You should be able to rewrite ex2 as:

 emps.ForEach(empl=>Console.WriteLine("Employee " + empl); 

Note that you do not need to explicitly specify the type as it is derived from emps

So ex1 will be split into:

 emps.OrderBy(e=>e.LastName).Select(e=>e.FirstName); 

For a more complete understanding of this and more, I really suggest the book Jon Skeets C # In Depth Second Edition

+3
source

UPDATE: This question was the subject of my blog on June 25, 2012 . Thanks for the great question!


With Linq, a range variable can be implicitly entered from the collection it comes from, but the foreach statement cannot do the same without the var keyword.

It is right.

Why is this?

I never know how to answer the why. So I pretend you asked another question:

There are two different ways in which you can introduce an implicit typing of a named variable. A named local variable, for a loop variable, a foreach loop variable, or using an operator variable can be implicitly entered by replacing "var" with its explicit type. The lambda parameter or query range variable can be implicitly entered, generally omitting its type.

Correctly.

This is inconsistency. The basic design principle is that inconsistencies should be avoided as this is confusing; the user naturally assumes that the mismatch conveys meaning. Can these functions be consistent?

Indeed, there are two ways in which they could be agreed upon. First, "var" is required everywhere for you to say:

 Func<double, double> f = (var x)=>Math.Sin(x); var query = from var customer in customers join var order in orders on customer.Id equals ... 

The whole design is a series of compromises. This matches the consistency test, but now seems awkward and verbose.

Secondly, you need to exclude "var" everywhere so you say:

 x = 12; // Same as "int x = 12;" using(file = ...) ... for(i = 0; i < 10; ++i) ... foreach(c in customers) ... 

In the first three cases, we unexpectedly added the feature of “implicitly declared locales” rather than “implicitly typed locales”. It seems strange and unrelated to C # to have a new local variable declared just because you assigned something to a name that was not previously used. This is the function we would expect in a language such as JScript or VBScript, not C #.

However, in the foreach block, the context shows that a local variable is being introduced. We could eliminate the “var” here without causing too much confusion, because the “in” is not mistaken for a job.

OK, so to summarize our capabilities:

  • Function 1: var is required everywhere.
  • Function 2: require var nowhere.
  • Function 3: requires var for locals, for loops and operations, but not for foreach loops, lambdas, or range variables.
  • Function 4: requires var for locals, for using loops and foreach, but not for lambdas or for range variables.

The first two have the benefits of consistency, but consistency is only one factor. The first is awkward. The second is too dynamic and confusing. The third and fourth seem plausible compromises, although they are incompatible.

The question then becomes: is the foreach loop variable more like a local variable or more like a lambda parameter? Clearly, this is more like a local variable; in fact, the foreach loop is specified as a rewrite in which the loop variable becomes a local variable. For consistency with the "for" loop and consistency using the foreach loop for C # 1.0 and C # 2.0, which requires some type, we choose option 4 as superior to the third option.

I hope that answers your question. If not, ask a much more specific question.

+14
source

It seems that "empl" is the string in the second example, because the select clause of the LINQ statement specifies e.FirstName. If you want it to include a list of employees, use the following:

 var sortedByLastname = from e in emps select e orderby e.LastName; 
0
source

This is due to the construction of the language, and not to the derivation of the type of the variable. The reason that foreach-loop cannot do the same without the var keyword is because foreach(var empl in list) and foreach(empl in list) mean different things (I'm not even sure the second one is legal) . The first one allocates a new variable, while the second (if it is legal) will use an already existing variable (the reason must be entered correctly). However, the for clause in LINQ is designed so that when you create for e in list e is created as a variable.

0
source

All Articles