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.