为什么C#不允许使用var同时声明多个变量?

49

给定以下内容:

// not a problem
int i = 2, j = 3;

所以让我感到惊讶的是这个:

// compiler error: Implicitly-typed local variables cannot have multiple declarators
var i = 2, j = 3;

无法编译。可能是因为我对此不理解(这也是我提出问题的原因)?

但是为什么编译器不能意识到我所指的是:

var i = 2;
var j = 3;

可以编译通过的代码。


3
这个帖子只有20分钟的历史记录。你希望Eric每小时都检查SO上的每个C#帖子吗? - CodesInChaos
2
顺便说一下,我知道这只是一个例子,但是当开发人员在int的位置使用var时,我总是感到很烦。它们的字母数量相同!在我看来,int甚至更容易输入 ;) - Dan Tao
9
@bzlm:首先,学会耐心。其次,我不“潜水”。第三,如果你想让我注意到某件事,请使用我的博客上的联系链接,我会尽快处理。我确实需要有时候专注于编译器的实际工作。 - Eric Lippert
5
@Rune FS:我大部分同意你的观点,但在一些情况下,类型的机制对代码的正确性和理解非常重要,在这些情况下,将类型明确地呈现出来是一个好主意。我认为有这个选项很好,这样你可以根据需要选择强调或弱化类型。 - Eric Lippert
2
@Cynthia:我理解你的观点。但请考虑一下,临时变量也是变量。当编译器编译“int x = a * b + c”时,它将其编译为“int x; int temp = a * b; x = temp + c;”。如果您非常注重显式类型,那么为什么编译器会在您的代表中默默生成一个推断类型的变量呢?我们应该要求您明确声明该变量,并明确声明其类型吗?您想在哪里划线呢? - Eric Lippert
显示剩余18条评论
5个回答

63

当我们设计这个功能时,我向社区询问了什么

var x = 1, y = 1.2;

这个问题是关于隐式类型声明的语义。问题和答案可以在以下链接找到:

http://blogs.msdn.com/b/ericlippert/archive/2006/06/26/what-are-the-semantics-of-multiple-implicitly-typed-declarations-part-one.aspx

http://blogs.msdn.com/b/ericlippert/archive/2006/06/27/what-are-the-semantics-of-multiple-implicitly-typed-declarations-part-two.aspx

简单来说,一半的回答认为将x和y都设为double是显然正确的,而另一半则认为将x设为int和y设为double是显然正确的。

(语言委员会指定了应该使用"double",并且我实际上在正式发布之前就已经以这种方式实现了代码。我们使用与隐式类型数组相同的类型推断算法,其中所有表达式必须可转换为最佳元素类型。)

当你的一半客户认为一件事情是“显然正确”的,而另一半认为相反的事情是“显然正确”的时候,你就有一个很大的设计问题了。解决方案是将整个过程设置为非法,并避免这个问题。


1
@Joan:我们将其删除,并用一个错误恢复系统替换了它,该系统会将“var x = a,y = b;”绑定为“var”被替换为“a”的类型。这样,您可以在“x。”和“y。”上获得IntelliSense,就好像它们都是“a”的类型一样。对于IDE体验来说,这似乎比一些试图找出最佳类型或每个类型的类型的复杂启发式更明智。 - Eric Lippert
9
@Marlon:首先,由于你声明的方式,“int x,y;”表达了真正的含义,即x和y都是包含int的变量,所以你在C语言的直觉是错误的。其次,你不得不考虑另一种语言(奇怪的)语义,并且在过程中改变了想法,这实际上证明了该特性完全不清晰和具有误导性,因此应该将其禁止。这也是我们所做的。 - Eric Lippert
在这些情况下,你不能只在模糊不清的情况下报错吗?有很多时候都会出现这种模糊不清的情况,所以整个功能就变成了一个错误,而不仅仅是模糊不清的情况。应该简单地说明“推断类型冲突;多个隐式类型变量必须解析为相同的类型。分开声明或使类型匹配。” - Dave Cousineau
1
@DaveCousineau:是的,你知道那听起来像什么吗? 工作 ,C#团队是Visual Studio发布的“长杆”,我们的日程比其他团队更加繁忙,所以每天我们迟到一天,VS就会滑落。你猜哪个开发人员担任了C#团队的“长杆”?那就是我。编写模糊检测器,然后编写测试用例和错误消息等所有这些内容,即使对于简单的功能,也需要多达数天。我想负责延迟VS以添加此类错误吗?我不想。 - Eric Lippert
1
@DaveCousineau:此外,还有长期因素需要考虑。今天将某个功能合法化意味着您不能重新考虑该决定并在明天使其非法,但反之通常不成立。如果C#团队今天决定要实现您提出的功能,则可以在不破坏任何人的情况下实现。但是,如果他们实现了一个看起来靠不住的功能,以后会后悔,那就永远无法更改。这表明应该在解析时将其设置为非法。 - Eric Lippert
显示剩余7条评论

44

这只是程序员和编译器可能混淆的另一点。

例如,这个是可以的:

double i = 2, j = 3.4;

但这是什么意思呢?

var i = 2, j = 3.4;

使用语法糖的话,这种无人需要的麻烦事会让人头痛--因此我怀疑你所说的情况永远不会得到支持。它涉及编译器试图变得过于聪明而导致的太多复杂性。


4
编译器可以捕捉到多个类型的赋值,并仅在这种情况下产生错误。这似乎只是一个设计选择。当然,可能有我不知道的技术原因。 - Ed S.
3
任何支持的事物都需要在设计、测试和支持方面付出成本。由于这个功能没有真正的好处,而且可能会让某些人感到困惑和/或沮丧,至少我认为不需要做出积极的决定来排除它。它只是不值得包含在C#功能集中。或者引用《星际迷航》中的一句话,“仅仅因为我们可以做某事......” - James Gaunt
3
编译器可以在第一遍中使用其中一种情况并解决它。而程序员可能会非常困惑。C++程序员可能会期望ijdouble,而其他人可能会期望iintjdouble,还有一些情况下则是编译错误!不过,他们共同的反应是讨厌编译器设计者做错了事情。 - Jaroslav Jandek
6
我已经看到了与语言编写者的这个对话,确实:原因就在这里。由于没有一种清晰明确的解释方式得到所有人的认可(最少惊讶等),最好还是不要解释。有些人肯定会认为它是double和double,而有些人则肯定会认为它是int和double... - Marc Gravell
4
因为在C#中,任何用逗号分隔的变量声明列表都必须具有相同的类型。所以,将开头的“double”替换为“var”会引入混淆;这样做突然改变了许多变量类型。此外,如果你把鼠标悬停在任何一个现有的“var”上,就可以看到当前推断出的类型。想象一下,在“var x=1, y="foo"”中把鼠标悬停在“var”上会是什么情况,这很令人困惑。 - KeithS
显示剩余20条评论

7

因为如果这个可以工作:

var i = 2, j = 3;

因为这个有效:

var i = 2;
var j = 3;

那么你可能希望这个工作:

var i = 2, j = "3";

因为这个有效:
var i = 2;
var j = "3";

即使在James Gaunt提出的情况中,它们都是数字类型,并且可以存储在同一类型的值中,那么i会是什么类型呢?

var i = 2, j = 3.4;

j 显然是一个 double 类型,但是 i 可以根据你期望的变量类型推断逻辑上的 int 或者 double 类型。无论如何实现,都会导致那些期望它按照另一种方式工作的人感到困惑。

为了避免所有这些混乱,它被简单地禁止了。就我个人而言,我不认为这是一个很大的损失;如果你想声明一个变量列表(在我的工作经验中本身就很少见),只需强制将它们类型化即可。


"根据您期望var推断类型的方式,我可以逻辑上是int或double。您已经通过说“var i = 2;”意味着i是int来正确地推理了这一点。如果人们无法通过这种非常简单的方式进行推理,那么这是他们智力不足的问题。这种推理非常简单易懂,并且在for循环中显然需要它,因为可能需要多个变量“for(var i = 0,j =3; ...)”。我认为反对此功能的整个论点都是无效的。" - XDS

4

我认为这太靠不住了。当两个变量是相同类型时,这是一个易于处理的特定情况,但在更一般的情况下,你必须考虑像下面这样的代码中什么是“正确”的:

var x = new object(), y = "Hello!", z = 5;

那么这些变量应该全部声明为object类型,因为它们唯一共同的类型就是object。或者x可以是object类型,ystring类型,zint类型吗?
一方面,你可能认为前者是正确的,因为以这种方式声明的变量(都在同一行)通常被认为是相同类型的。另一方面,也许你会认为后者是正确的,因为var关键字通常应该让编译器为你推断出最具体的类型。
最好完全禁止这种情况,而不是费心去解决它应该如何行事,因为它本身也不是一个“杀手级”特性。
至少这是我的看法/猜测。

1
规则可以是一个声明中的所有局部变量必须导致相同的推断类型。 - CodesInChaos
1
你仍然可能会遇到所有值都是一种推断类型的情况,但如果每个值都单独声明,则它们将成为不同的推断类型。无论哪种方式(单独或组合推断),它们都可以正常工作,但会让那些期望以另一种方式工作的人感到困惑。 - KeithS
@CodeInChaos,@KeithS:我同意Keith的观点。没有人真正否认它可能以某种方式工作;我认为问题在于,无论那种假设的方式是什么,它也可能以相反的方式工作。 - Dan Tao
1
我不明白你的意思,KeithS。我的建议是只有在所有类型相同(而不仅仅是可转换为相同类型)的情况下才允许这样的var语句。因此,var i=1,j=2是有效的,var i=1.0,j=2则不是。但我同意JamesGaunt的看法,这可能不值得规范、编码、测试的成本。 - CodesInChaos
@CodeInChaos:所以你的意思是完全相同的类型。毕竟,所有类型至少都是object。我认为Keith(和我)认为你只是想让编译器为所有变量选择最具体的公共类型。 - Dan Tao

1

我认为这是因为编译器可能认为以下代码是相同的:

var i = 2, j = "three"

然而这两个变量肯定不是同一种类型。


在问题的示例中,这不适用。 - bzlm
@bzlm 为什么你这么想呢?问题是关于令人惊讶的点,而这个答案说明了为什么它不应该那么令人惊讶。 - Ilya Dvorovoy
+1 来抵消 -1。虽然有点简洁,但这个答案包含了一些得到赞同的答案的相同推理。 - user166390
@pst 谢谢,那就是我取消删除的唯一原因,因为肯定有一个更明确的答案。 - Ilya Dvorovoy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接