为什么需要声明?

13

我目前正在教授一位同事.Net,他问了我一个让我困惑的问题。

为什么我们必须要声明?

如果变量是隐式类型,为什么我们还需要声明呢?

Animal animal = new Animal();

变成

var animal = new Animal();

可能成为

animal = new Animal();

隐式类型声明仍然意味着这是一个静态类型的变量。

如果将两种不同类型分配给变量,且它们没有共享基类(除了 object),那可能会导致编译器错误。

这是否有技术上的限制或只是出于风格原因我们喜欢这样做?


8
如何知道你是想声明一个新变量还是使用已有的变量? - starskythehutch
1
类型推断是C# 3中的新功能。在那之前,var不存在。此外,即使可以推断出类型,对于复杂表达式,记录预期类型可能更清晰。 - Damien_The_Unbeliever
4
@starskythehutch的意思是,编译器怎么知道你是个笨蛋打错了变量名。事实上,在那些像你建议的语言中,这可能是最常见的错误。 - Aron
1
在我看来,这使得代码更加清晰,你不必再去想你是在使用之前声明的变量还是新的变量。 - noisy cat
2
如何定义变量的作用域? - A. Tapper
显示剩余5条评论
6个回答

25
当然,这是可能的。 我可以想到几个你不想要这样做的原因:
  1. 变量的作用域是什么?如果你不告诉编译器,那么就不清楚了。在两种方法中的 animals 变量会成为一个私有变量还是两个方法作用域变量?
  2. 如果名称是错别字怎么办?你永远不会知道。
  3. 如果你已经给这个变量赋值,然后尝试分配一个与最后一个不兼容的新值(即 javascript 风格)(感谢 Mario Stoiov)。

澄清一下,一个值是由一个可丢弃对象生成的,但是它在其他地方被使用。如果没有明确的作用域,你就无法处理这个可丢弃对象,并同时保持你分配的值在作用域内。 - Aron
@patrick。1)成员级别变量将在类级别声明,否则遵循普通规则。2)语言保护我们免受自己的伤害,这是一个有效的理由。3)这将是编译器错误;如果认为方法应该小而有限制,则不应将未声明的变量用于方法,就像匿名类型一样,这不应该是问题(除了拼写错误!)。 - Paul Spencer
@PatrickHofman,错别字和“任何事情都有可能”的评论已经涵盖了我需要对同事说的话。谢谢。 - Paul Spencer

13

一个非常重要的原因是,它有助于防止因为变量名误打误拼而导致的错误。

想象一下,你想重新给字符串myString赋一个新值:

myString = "New value";

但是你不小心打出了这个:

myStrimg = "New value";

这将导致编译时错误。但是,如果根据您的问题允许隐式创建变量,则会悄悄地创建一个新变量,并产生可预测的滑稽结果...


11

如Brad Smith所建议的http://www.brad-smith.info/blog/archives/336

一些程序员似乎有使用 var 定义所有变量的倾向。当然,语言不会阻止你这样做,MSDN也承认这是一种“语法便利”......但它也强烈警告说:

使用 var 至少可能使其他开发人员更难理解你的代码。出于这个原因,C#文档通常只在需要时使用 var。

“隐式类型本地变量 (C# 编程指南)”,MSDN

我最近发现常用的工具 ReSharper 几乎强制要求大量使用 var。坦白地说,这并没有帮助到情况。有些开发人员试图辩称 var 在某种程度上提高了可读性和更广泛的编码实践,例如这篇文章:

通过使用 var,你强迫自己更多地考虑如何命名方法和变量,而不是仅仅依赖于类型系统来提高可读性,这更像是一个实现细节......

var improves readability, Hadi Hariri

我同意上面引用的前提,但不同意最后的结果。相反,过度使用和误用 var 可能会导致一些非常糟糕的习惯......

让我们看看反对广泛使用 var(并支持其节约、正确使用)的论点:

隐式类型变量失去描述性

类型名称在本地变量声明中提供了一个额外的描述层次:

 // let's say we have a static method called
 GetContacts() // that returns System.Data.DataTable  
 var individuals = GetContacts(ContactTypes.Individuals); 

 // how is it clear to the reader that I can do this?   
 return individuals.Compute("MAX(Age)", String.Empty);
我的变量名非常具有描述性;它可以区分使用GetContacts()生成的任何其他变量,以及类型为DataTable的其他变量。当我操作该变量时,我知道它是指个别联系人,并且从它们派生的任何内容都将属于该上下文。但是,如果在声明中没有指定类型名称,我将失去它所提供的描述性...
   // a more descriptive declaration   
   DataTable individuals = GetContacts(ContactTypes.Individuals) 

当我回顾这段代码时,我不仅知道变量在概念上代表什么,还知道它在结构和用法方面的表示;而在前一个例子中缺乏这种信息。

额外说明:

以下是基于隐式变量声明的一个合理使用的好/坏例子...

  • 好例子:

     var numbers = new int[] {1, 2, 3, 4};
    
     var stringbuilder = new StringBuilder();
    
     var cars = new List();
    
     var orders = new Dictionary();
    

+/- 同意任何一种方式(但更喜欢明确声明):

 int pages = 10;
 string username = “john”;
var username = “john”;
var order = GetOrder(orderId); // ok if the type is Order, otherwise not
 for (var x = 1; x < 10; x++)
  • 不好:

       var settings = GetInboxSettings(); // not obvious at all
    
      var userId = GetUserId(); // ambigous, is this guid, string, int or a custom UserId object?
    
       Dictionary orders = new Dictionary(); // redundant
    

2
当我们声明一个变量xxx时,我们向工具表明以下内容:
  • 为一个对象腾出空间
  • 该对象将在此范围内存在
  • 并且是这种类型(可选)
我们对人类说的是:
  • 一个名为xxx的对象存在于此范围内
  • 是这种类型(可选)
范围对于这两个方面都是至关重要的,因为工具需要知道变量的存活时间,而人类需要看到变量的生存位置。类型可能是一个很好的信息,但许多语言可以没有它,所以我认为它不是很重要,但因人而异。
编译器可以确定变量的作用域,例如通过决定变量名称的第一次遇到是变量的声明,而任何下面具有相同名称的单词都是对该变量的引用。然而,人类无法成功地跟踪这种复杂性。
因此,我认为我们有一个好的理由来声明变量:告诉阅读我们代码的人它的存在。声明变量增加了它们的可见性,并澄清了对程序理解至关重要的信息。

如果我们仅限于方法,就范围而言,编译器可以只说它所看到的第一个范围是它所在的范围。就可见性而言,当变量被分配时,人类会看到它,使用var声明变量是告诉人类这是我使用此变量的第一个位置/范围。 - Paul Spencer
将限制仅限于方法,然后声明变量确实是“无用的”,因为该变量不会离开方法,除非作为参数或返回变量。但是,这会稍微复杂化人类检测变量在方法中实例化的行为。当然,使用小方法可以使这一点无关紧要,但那是另一个话题 :) - samy

1

可能有很多原因。我能想到的一个原因是属性/字段引用与新变量之间的歧义。

然而,C#编译器团队可能仍然可以开发这样的功能。但使用var简化了一切。我们节省了设计、开发、测试和维护的工作量。最重要的是,它使您的代码更易读。


0

嗯,我并不否认这里的一些答案所提出的事实。相反,我想以不同的方式回答:

int count;
if(someConditionIsTrue)
    count = 3;
else count = 1;

我不能在这里使用 "var count"。我可以吗? 现在以下两行哪一行看起来比较好:

Tuple<int, string, bool, float> tuple = new Tuple<int, string, bool, float>(1, "p", true, 3.0f);

或者

var tuple = new Tuple<int, string, bool, float>(1, "p", true, 3.0f); 

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