c# - Linq 隐式类型范围变量

标签 c#

使用 Linq,范围变量 (e) 可以从它来自的数组/集合 (emps) 隐式类型化,但是没有 var 关键字或类型的 foreach 语句不能做同样的事情。这是为什么?

在 ex1 中,编译器知道 e 是 Employee 类型,而无需给出 var 关键字或任何东西。为什么 ex2 中的 foreach 循环不能做同样的事情,你必须提供类型(无论是它的 var 还是某种类型)。

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);
        }

这可能分析过度了,但我正在努力弄清为什么会这样。

答案很可能是 Linq 查询语法设置为自动推断范围变量的类型,而 foreach 语句不是。谁能帮忙解释一下这是为什么?

最佳答案

更新:This question was the subject of my blog on June 25th, 2012 .感谢您提出很好的问题!


With Linq, the range variable can be implicitly typed from the collection it is coming from, but a foreach statement cannot do the same thing without the var keyword.

没错。

Why is this?

我从来不知道如何回答“为什么”的问题。所以我假装你问了一个不同的问题:

There are two distinct ways that a named variable may be implicitly typed. A named local variable, for loop variable, foreach loop variable, or using statement variable may be implicitly typed by substituting "var" for its explicit type. A lambda parameter or query range variable may be implicitly typed by omitting its type altogether.

正确。

That is an inconsistency. A basic design principle is that inconsistency is to be avoided because it is confusing; the user naturally assumes that an inconsistency conveys meaning. Could these features have been made consistent?

确实,有两种方法可以使它们保持一致。第一种是到处要求“var”,这样你会说:

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 ...

所有的设计都是一系列的妥协。这符合一致性测试,但现在感觉笨拙和冗长。

二是把“var”处处去掉,这样你就会说:

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

在前三种情况下,我们现在无意中添加了“隐式声明局部变量”而不是“隐式类型局部变量”的特征。声明一个新的局部变量似乎很奇怪并且不像 C# 那样,只是因为您将一些东西分配给了一个以前没有使用过的名称。这是我们期望在 JScript 或 VBScript 等语言(而不是 C#)中使用的那种功能。

但是,在 foreach block 中,从上下文可以清楚地看出引入了局部变量。我们可以在此处删除“var”而不会引起太多混淆,因为“in”不会被误认为是赋值。

好的,让我们总结一下我们可能的特征:

  • 特征 1:到处都需要 var。
  • 特征 2:无处需要 var。
  • 特性 3:在局部变量、for 循环和 usings 上需要 var,但在 foreach 循环、lambda 或范围变量上不需要 var
  • 特性 4:在局部变量上需要 var,for 循环使用和 foreach,但不是 lambda 或范围变量

前两者具有一致性的好处,但一致性只是一个因素。第一个很笨重。第二个过于动态和困惑。第三和第四点似乎是合理的妥协,尽管它们并不一致。

接下来的问题是:foreach 循环变量更像一个局部变量 还是更像一个lambda 参数?显然它更像是一个局部变量;事实上,foreach 循环被指定作为重写,其中循环变量成为局部变量。为了与“for”循环保持一致,并与 foreach 循环的 C# 1.0 和 C# 2.0 用法保持一致,这需要某种类型,我们选择选项四优于选项三。

我希望这能回答您的问题。如果没有,请提出更具体的问题。

关于c# - Linq 隐式类型范围变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9798544/

相关文章:

C# var 关键字用法

c# - OrderedDictionary 和正则表达式

c# - 实现接口(interface)的数组的隐式类型化

c# - MVC4 如何动态地将行项目添加到 EditorFor 字段?

c# - 使用 C# 在 Word docx 中填充文档变量

c# - 我可以在按钮内绘制形状吗?

c# - wcf服务如何授权

C# If 语句和 Random 类表现得很奇怪

C# 工具提示未出现在 "Show"

c# - TimeZoneInfo.GetUtcoffset 的可靠性如何?