在C#中使用var关键字

时间:2020-03-05 18:46:58  来源:igfitidea点击:

与同事讨论了在C3中使用'var'关键字后,我想知道人们对于通过var进行类型推断的适当用法有何看法?

例如,我宁愿在可疑的情况下懒惰地使用var,例如:-

foreach(var item in someList) { // ... } // Type of 'item' not clear.
var something = someObject.SomeProperty; // Type of 'something' not clear.
var something = someMethod(); // Type of 'something' not clear.

var的更多合法用法如下:-

var l = new List<string>(); // Obvious what l will be.
var s = new SomeClass(); // Obvious what s will be.

有趣的是LINQ似乎是一个灰色区域,例如:-

var results = from r in dataContext.SomeTable
              select r; // Not *entirely clear* what results will be here.

显然将产生什么结果,因为它将是实现IEnumerable的类型,但是以声明新对象的var相同的方式,它并不是完全显而易见的。

当涉及到对象的LINQ时,甚至更糟,例如:-

var results = from item in someList
              where item != 3
              select item;

这不比等价的foreach(someList中的var item){// ...}等价。

例如,如果我们将查询的结果放入接受了IEnumerable <int>和IEnumerable <double>的重载方法中,调用者可能会无意中传递了错误的类型,那么这里确实存在有关类型安全的问题。

var确实保持强类型,但是问题实际上是类型在定义上不立即变得危险吗?当重载意味着当我们无意将错误类型传递给方法时,可能不会发出编译器错误时,这种情况会放大。

解决方案

回答

我认为var的使用应与明智选择的变量名结合使用。

我不会在foreach语句中使用var,只要它不是这样:

foreach (var c in list) { ... }

如果更像这样:

foreach (var customer in list) { ... }

...那么,阅读代码的人更有可能理解什么是"列表"。如果我们可以控制列表变量本身的名称,那就更好了。

同样的情况也适用于其他情况。这是毫无用处的:

var x = SaveFoo(foo);

...但这是有道理的:

var saveSucceeded = SaveFoo(foo);

我猜每个人都有。我发现自己正在这样做,这简直太疯狂了:

var f = (float)3;

我需要某种12步var程序。我的名字叫马特(Matt),我(ab)使用var。

回答

在办公室中,出于与我们所述相同的原因,我们的CTO明确禁止使用var关键字。

我个人发现var的用法仅在新的对象声明中有效,因为该对象的类型在语句本身中是显而易见的。

对于LINQ查询,我们可以将结果解析为:

IEnumerable<TypeReturnedBySelectObject>

回答

当我开始使用var关键字时,我也有同样的担忧。
但是随着时间的流逝,我已经习惯了,并且不打算回到显式变量类型。
Visual Studio的compile \ intellisense在使隐式类型变量的工作变得更加容易方面做得很好。

我认为遵循正确的命名约定可以比显式键入更好地理解代码。

似乎是类似的问题,例如"应该在变量名中使用前缀吗?"。
坚持使用好的变量名,让编译器考虑变量类型。

回答

有人不喜欢对var的批评。所有答案都下调了。

@乔恩·林贾普(Jon Limjap):
我知道。 :)我的意思是像VB6一样,可读性下降了。我不想依靠Intellisense来确定给定变量的类型。我希望能够仅使用源就可以弄清楚。

命名约定对我已经使用好名字没有帮助。我们要回到前缀吗?

回答

我认为VAR的关键是仅在适当的地方使用它,即在Linq中做它会促进的事情时(可能在其他情况下)。

如果我们有某种类型的东西,那么我们应该使用它而不是简单的懒惰(与创造性的懒惰相对,这通常被鼓励,好的程序员经常努力工作以变得懒惰,可以将其视为源代码)首先。

首先,全面禁止与滥用结构一样糟糕,但是确实需要一个明智的编码标准。

还要记住的另一件事是,它不是VB类型的var,因为它不能更改类型,它是一个强类型变量,其类型只是被推断出来的(这就是为什么有人会争论说,使用它并非不合理) (例如,foreach),但出于可读性和可维护性的原因,我不同意。

我怀疑这将要运行(-:

墨菲

回答

var难以实现的一种特殊情况:脱机代码审查,尤其是纸上审查。

我们不能为此依赖鼠标悬停。

回答

我仍然认为var在某些情况下可以使代码更具可读性。如果我有一个具有Orders属性的Customer类,并且想将其分配给变量,则只需执行以下操作:

var orders = cust.Orders;

我不在乎Customer.Orders是否为IEnumerable <Order>,ObservableCollection <Order>或者BindingList <Order>,我只想将该列表保留在内存中以对其进行迭代或者获取其计数或者其他内容稍后的。

将以上声明与:

ObservableCollection<Order> orders = cust.Orders;

对我来说,类型名称只是噪音。如果我返回并决定更改Customer.Orders的类型(例如,从" ObservableCollection <Order>"更改为" IList <Order>`"),那么我就需要更改该声明,而这是我所不需要的如果我首先使用var来做。

回答

@erlando,出于好奇,为什么在查看源代码时需要知道变量的类型?

在我的实践中,我发现仅当我在代码中使用变量类型时,变量类型才对我很重要。

如果我试图在someVar编译器上执行一些不适当的操作,很高兴给我一个错误\警告。

如果我了解在给定的上下文中为什么使用它,我真的不在乎someVar的类型。

回答

我广泛使用var。曾有人批评说这会降低代码的可读性,但没有论据支持该主张。

诚然,这可能意味着我们不清楚要处理的是哪种类型。所以呢?这实际上是分离设计的重点。在处理接口时,我们对变量的类型很不感兴趣。 var更进一步,这是正确的,但我认为从可读性的角度来看,该参数保持不变:程序员实际上不应该对变量的类型感兴趣,而应该对变量的功能感兴趣。这就是Microsoft为何也将类型推断鸭子类型称为"为什么"的原因。

那么,当我使用var声明变量时,它做什么呢?很简单,它可以完成IntelliSense告诉我的一切。关于C的任何忽略IDE的推理都不现实。实际上,每个Ccode都在支持IntelliSense的IDE中进行编程。

如果我使用的是var声明的变量,并且对变量的作用感到困惑,那么我的代码根本就出了问题。 var不是原因,它只会使症状可见。不要怪信使。

现在,Cteam发布了一个编码指南,指出" var"仅应用于捕获创建匿名类型的LINQ语句的结果(因为在这里,我们没有" var"的真正替代品)。好吧,把那拧紧。只要Cteam对这个准则没有给我一个合理的论据,我将忽略它,因为从我的专业和个人观点来看,它纯粹是胡扯。 (抱歉;我没有指向相关指南的链接。)

实际上,对于为什么不应该使用var有一些(表面上的)很好的解释,但是我仍然相信它们在很大程度上是错误的。以可搜索性为例:作者声称var使得搜索使用MyType的地方变得困难。正确的。接口也是如此。实际上,为什么我要知道在哪里使用该类?我可能对它的实例化位置更感兴趣,并且仍然可以搜索它,因为必须在某个地方调用其构造函数(即使是间接完成的,也必须在某个地方提到类型名称)。

回答

@aku:一个例子是代码审查。另一个示例是重构方案。

基本上,我不想用鼠标进行类型搜索。它可能不可用。

回答

我不知道有什么大不了的..

var something = someMethod(); // Type of 'something' not clear <-- not to the compiler!

我们仍然对"某物"具有完整的智能理解,对于任何模棱两可的情况,我们都可以进行单元测试,对吗? ( 你? )

它不是varchar,也不是暗淡的,并且肯定不是动态的或者弱类型的。它正在停止像这样的马丹:

List<somethinglongtypename> v = new List<somethinglongtypename>();

并将总思路减少到:

var v = new List<somethinglongtypename>();

不错,还不如:

v = List<somethinglongtypename>();

但这就是Boo的目的。

回答

@erlando,

谈论重构,通过将新类型的实例分配给一个变量而不是在多个位置进行更改来更改变量类型似乎要容易得多,不是吗?

至于代码审查,我认为var关键字没有太大问题。在代码审查期间,我更喜欢检查代码逻辑而不是变量类型。当然,在某些情况下,开发人员可以使用不合适的类型,但我认为此类情况的数量非常少,这并不是我停止使用var关键字的原因。

所以我重复我的问题。为什么变量类型对我们很重要?

回答

这是一个品味问题。当我们习惯于动态键入语言时,有关变量类型的所有这些麻烦就消失了。也就是说,如果我们曾经喜欢过它们(我不确定每个人是否都可以,但是我愿意)。

C#的var很酷,因为它看起来像是动态类型,但实际上是静态类型,编译器会强制使用正确的用法。

变量的类型并不那么重要(前面已经说过)。从上下文(与其他变量和方法的交互)及其名称中应该比较清楚,并且它的名称不要让customerList包含一个" int" ...

我仍然在等待老板对这个问题的看法,我大胆地"继续"使用3.5中的任何新结构,但是我们将如何进行维护?

回答

在我们将" IEnumerable <int>"和" IEnumerable <double>"进行比较时,我们不必担心如果传递了错误的类型,则代码无论如何都不会编译。

不用担心类型安全,因为var不是动态的。这只是编译器的魔力,我们进行的任何类型的不安全调用都将被捕获。

Linq绝对需要Var

var anonEnumeration =
    from post in AllPosts()
    where post.Date > oldDate
    let author = GetAuthor( post.AuthorId )
    select new { 
        PostName = post.Name, 
        post.Date, 
        AuthorName = author.Name
    };

现在看一下intellisense中的anonEnumeration,它将出现类似IEnumerable &lt;'a>的内容。

foreach( var item in anonEnumeration ) 
{
    //VS knows the type
    item.PostName; //you'll get intellisense here

    //you still have type safety
    item.ItemId;   //will throw a compiler exception
}

Ccompiler是非常聪明的匿名类型,如果它们的属性匹配,则分别生成的匿名类型将具有相同的生成类型。

除此之外,只要我们具有智能,就可以在上下文清晰的任何地方使用var。

//less typing, this is good
var myList = new List<UnreasonablyLongClassName>();

//also good - I can't be mistaken on type
var anotherList = GetAllOfSomeItem();

//but not here - probably best to leave single value types declared
var decimalNum = 123.456m;

回答

我将var拆分到所有位置,对我来说唯一可疑的位置是内部短类型,例如我更喜欢int i = 3;而不是var i = 3;

回答

@基思-

In your comparison between
  IEnumerable<int> and
  IEnumerable<double> you don't need to
  worry - if you pass the wrong type
  your code won't compile anyway.

如果将方法重载到IEnumerable <int>和IEnumerable <double>上,则可能会默默地将意外的推断类型(由于程序中的其他更改)传递给错误的重载,从而导致错误的行为,这不是真的。

我想问题是这种情况出现的可能性有多大!

我猜问题的一部分是,如果不清楚某个东西是什么类型(尽管是强类型并且编译器完全理解它是什么类型),那么var会给给定声明带来多少混乱,有人可能会掩盖一个类型安全性错误,或者至少需要更长的时间来理解一段代码。

回答

我在以下情况下使用var:

  • 当我必须(结果是匿名的)时
  • 当类型与代码在同一行时,例如var emp = new Employee();

很明显,我们需要一个Employee(因为我们正在创建一个新的Employee对象),所以

Employee emp = new Employee() any more obvious?

当无法推断类型时,例如,我不使用var

var emp = GetEmployee();

因为返回类型不是立即显而易见的(是在Employee上,还是在IEmployee上,与Employee对象完全无关的东西,等等?)。

回答

在刚刚转换到3.0和3.5框架之后,我了解了该关键字,并决定尝试一下。在提交任何代码之前,我已经意识到它似乎是向后的,就像回到ASP语法一样。因此,我决定拨开高层,看看他们的想法。

他们说继续吧,所以我用它。

这样说,我避免在需要调查类型的地方使用它,例如:

var a = company.GetRecords();

现在这可能只是个人问题,但我立即无法查看并确定它是Record对象的集合还是代表记录名称的字符串数组。无论哪种情况,我都认为显式声明在这种情况下很有用。

回答

我必须同意马特·汉密尔顿的观点。

与好的变量名一起使用时,Var可以使代码更具可读性和可理解性。但是当使用不当时,var也会使代码像Perl一样无法阅读和理解。

列出var的优缺点并不会对我们有多大帮助。这是常识性的情况。更大的问题是可读性与可写性之一。许多开发人员不在乎其代码是否可读。他们只是不想输入太多。我个人是个阅读>写信的人。

回答

那种情况下的克朗兹(两者都超载)有关系吗?如果我们有两个采用不同类型的重载,那么我们实际上是在说两个重载都可以传递并执行相同的操作。

我们不应有两个重载根据传递的类型执行完全不同的操作。

尽管在这种情况下我们可能会感到困惑,但它仍然是完全类型安全的,但我们只会有人调用错误的方法。

回答

我不明白为什么人们开始这样的辩论。真正的目的无非是发动火焰战,然后一无所获。现在,如果Cteam试图逐步淘汰一种风格,而转向另一种风格,那么我可以看到为每种风格的优点争论的理由。但是由于两种语言都将保留在该语言中,所以为什么不使用我们喜欢的语言并让每个人都做同样的事情。这就像每个人都喜欢的三元运算符的使用:有些喜欢它,有些不喜欢。归根结底,它对编译器没有影响。

这就像和兄弟姐妹争论,哪个是我们最喜欢的父母:没关系,除非他们要离婚!

回答

静态类型是关于合同的,而不是源代码。有一种想法是需要将静态信息放在一行上,而"应该"是一种很小的方法。通用准则建议每种方法很少超过25行。

如果一个方法足够大,以至于我们无法跟踪该方法中的单个变量,那么我们正在做其他错误,相比之下,对var的任何批评都会变得苍白无力。

实际上,var的一个很好的论据是它可以使重构更简单,因为我们不必担心声明过于严格(例如,应该使用IList <>或者IEnumerable <>时使用List <>)。 )。我们仍然想考虑新方法的签名,但是至少我们不必返回并更改声明以匹配。

回答

我发现使用var关键字实际上使代码更具可读性,因为我们只是习惯于跳过'var'关键字。当我们真的不在乎特定类型是什么时,无需一直向右滚动即可确定代码在做什么。如果我真的需要知道下面的"项目"类型,只需将鼠标悬停在它上面,Visual Studio就会告诉我。换句话说,我宁愿阅读

foreach( var item in list ) { DoWork( item ); }

一遍又一遍

foreach( KeyValuePair<string, double> entry in list ) { DoWork( Item ); }

当我尝试摘要代码时。我认为这可以归结为个人喜好。我将依靠这一常识-对重要内容(安全性,数据库使用,日志记录等)保存强制执行标准。

-艾伦

回答

我们采用了"人为准则,而不是机器准则"的精神,这是基于我们在维护模式下花费的时间比在新开发上花费的时间长很多倍的假设。

对我来说,这排除了编译器"知道"变量确定的类型的论点,因为编译器停止了代码的编译,但是当下一个开发人员正在读取代码时,我们不能第一次编写无效的代码。他们需要6个月的时间才能推断出变量在正确或者错误地做什么,并能够快速确定问题的原因。

因此,

var something = SomeMethod();

已被我们的编码标准禁止,但我们的团队鼓励以下行为,因为这会提高可读性:

var list = new List<KeyValuePair<string, double>>();
FillList( list );
foreach( var item in list ) {
   DoWork( item ); 
}

回答

来自团队高级软件设计工程师Eric Lippert:

为什么引入var关键字?

There are two reasons, one which
  exists today, one which will crop up
  in 3.0.
  
  The first reason is that this code is
  incredibly ugly because of all the
  redundancy:
  
  Dictionary<string, List<int>> mylists = new Dictionary<string, List<int>>();
  
  And that's a simple example – I've
  written worse. Any time you're forced
  to type exactly the same thing twice,
  that's a redundancy that we can
  remove. Much nicer to write
  
  var mylists = new Dictionary<string,List<int>>();
  
  and let the compiler figure out what
  the type is based on the assignment.
  
  Second, C# 3.0 introduces anonymous
  types. Since anonymous types by
  definition have no names, you need to
  be able to infer the type of the
  variable from the initializing
  expression if its type is anonymous.

强调我的。整个文章,C3.0仍然是静态键入的,老实说!随后的系列文章也不错。

这就是var的作用。其他用途可能效果不佳。与JScript,VBScript或者动态类型的任何比较都是完全不正确的。再次注意,为了使某些其他功能在.NET中起作用,必须使用" var"。

回答

对我来说,对var的反感说明了.NET中双语的重要性。对于同样使用VB .NET的C程序员来说,var的优势在直观上显而易见。标准声明:

List<string> whatever = new List<string>();

在VB .NET中相当于键入以下内容:

Dim whatever As List(Of String) = New List(Of String)

但是,没有人在VB .NET中这样做。这样做很愚蠢,因为自从.NET的第一个版本以来,我们已经能够做到这一点...

Dim whatever As New List(Of String)

...这将创建变量并将其全部初始化为一个紧凑的行。啊,但是如果我们要使用IList &lt;string>,而不是List &lt;string>,该怎么办?好吧,在VB .NET中,这意味着我们必须执行以下操作:

Dim whatever As IList(Of String) = New List(Of String)

就像我们必须使用C#一样,显然不能将var用于:

IList<string> whatever = new List<string>();

如果我们需要类型有所不同,可以。但是,良好编程的基本原理之一是减少冗余,而这正是var所做的。

回答

使用它来实现匿名类型。其他任何用途都太远了。就像许多在C上长大的人一样,我习惯于在类型声明的左边。除非必须,否则我不会在右边看。对任何旧声明使用var会使我一直这样做,我个人觉得很不舒服。

那些说"没关系,用自己满意的东西"的人并没有看到全部。每个人都会在某一点或者另一点拾取别人的代码,并且必须处理他们在编写代码时所做的任何决定。不得不处理根本不同的命名约定或者经典的抱怨支撑样式,而又没有添加整个" var"或者" var"的东西,这已经够糟糕的了。最糟糕的情况是,一个程序员没有使用var,然后一个维护者喜欢它,并使用它来扩展代码。所以现在你有一个邪恶的烂摊子。

标准恰好是一件好事,因为它们意味着我们更有可能拾取随机代码并能够快速使用它。不同的事物越多,获得的难度就越大。转变为"无处不在"的风格有很大的不同。

我不介意动态打字,也不会介意使用针对他们设计的语言进行隐式打字。我很喜欢Python。但是Cwas被设计为一种静态显式类型的语言,这就是它应该保留的方式。打破匿名类型的规则已经很糟糕了。我不满意让别人更进一步,打破语言惯用法。现在精灵已经被淘汰了,它永远也不会退缩。Cwill陷入了阵营。不好。

回答

我认为人们不了解var关键字。
他们将其与Visual Basic / JavaScript关键字混淆,
这是完全不同的野兽。

许多人认为var关键字暗示
弱类型(或者动态类型),而实际上是顺式和强类型。

如果我们在javascript中考虑此问题:

var something = 5;

我们被允许:

something = "hello";

对于c#,编译器将从第一条语句中推断出类型,
导致某些东西的类型为" int",因此第二条语句将导致
有一个例外。

人们只需要了解使用var关键字并不意味着
动态类型输入,然后决定要使用var关键字的程度,
知道它将在编译内容上完全没有区别。

确保引入了var关键字以支持匿名类型,
但是如果你看这个:

LedDeviceController controller = new LedDeviceController("172.17.0.1");

这非常冗长,而且我敢肯定,即使没有更多内容,它也具有可读性:

var controller = new LedDeviceController("172.17.0.1");

结果是完全一样的,所以是的,我在整个代码中都使用了它

更新:

也许,也许……他们应该使用另一个关键字,
那么我们就不会进行讨论了……也许是"推断"关键字而不是" var"

回答

var对于匿名类型是必不可少的(正如之前对该问题的回答之一所指出的那样)。

我将关于它的优缺点的所有其他讨论归为"宗教战争"。我的意思是对...的相对优点进行比较和讨论。

var i = 5;
int j = 5;

SomeType someType = new SomeType();
var someType = new SomeType();

...完全是主观的

隐式键入意味着使用var关键字声明的任何变量都不会受到运行时的惩罚,因此归结为关于使开发人员感到高兴的争论。

回答

从CodingHorror上有关此问题的帖子中被盗:

不幸的是,我们和其他所有人几乎都错了。尽管我同意冗余并不是一件好事,但是解决此问题的更好方法是执行以下操作:

MyObject m = new();

或者,如果我们要传递参数:

人p = new(" FirstName"," LastName);

在创建新对象时,编译器从左侧而不是右侧推断类型。与" var"相比,它还有其他优点,因为它也可以在字段声明中使用(还有其他一些领域也可能有用,但是在这里我将不再赘述)。

最后,它并不是要减少冗余。不要误会我的意思," var"在Cfor匿名类型/投影中非常重要,但是当我们混淆了正在使用。不得不多次键入两次,但是将其声明为零次则太少了。

Nicholas Paldino .NET / CMVP于2008年6月20日08:00 AM

我猜想,如果我们主要关心的是必须减少键入的内容,那么没有任何论点会影响我们使用它。

如果我们只想成为查看我们代码的人,那么谁在乎呢?否则,在这种情况下:

var people = Managers.People

很好,但是在这种情况下:

var fc = Factory.Run();

它会缩短我的大脑可能从代码的"英语"开始形成的任何立即类型的推论。

否则,只需对可能需要在项目上工作的其他人做出最好的判断和编程"礼貌"。

回答

我不使用var,因为它与CC / C ++ / Java的根源背道而驰。即使这是一个编译器技巧,它也使该语言感觉像是不太强类型化的语言。也许20多年的C根深蒂固地笼罩在我们(反瓦尔族人民)的脑海中,我们应该在等式的左侧和右侧都拥有该类型。

话虽如此,但我可以看到它对于长泛型集合定义和长类名的好处,例如encodinghorror.com示例,但是在其他地方(例如string / int / bool)我真的看不到这一点。特别

foreach (var s in stringArray)
{

}

节省3个字符!

对我来说,主要的烦恼是无法看到var表示方法调用的类型,除非将鼠标悬停在方法上或者F12上。

回答

没有,除了不必两次键入类型名称。 http://msdn.microsoft.com/en-us/library/bb383973.aspx

回答

我曾经认为var关键字是一个伟大的发明,但我对此进行了限制

  • 仅在明显是什么类型的情况下使用var(不滚动或者查看返回类型)

我意识到这对我没有任何好处,并且从我的代码中删除了所有var关键字(除非特别需要它们),因为我现在认为它们使代码的可读性较差,特别是对于其他阅读代码的人。

它隐藏了意图,并且在至少一个实例中,由于假设类型而导致某些代码中的运行时错误。

回答

大多数人忽略的是:

var something = new StringBuilder();

通常打字速度不如

StringBuilder something = KEY'TAB'();

回答

如果我们很懒,并且将var用于匿名类型以外的任何其他类型,则在此类变量的命名中应要求使用匈牙利表示法。

var iCounter = 0;

活着!

男孩,我想念VB吗?

回答

从关于该主题的讨论中,结果似乎是:

好:varcustomers = newList &lt;Customer>();

有争议:varcustomers = dataAccess.GetCustomers();

忽略" var"在魔术上有助于重构的误解,对我而言,最大的问题是人们坚持认为,"只要可以枚举集合,它们就不会在乎返回类型是什么"。

考虑:

IList<Customer> customers = dataAccess.GetCustomers();

var dummyCustomer = new Customer();
customers.Add(dummyCustomer);

现在考虑:

var customers = dataAccess.GetCustomers();

var dummyCustomer = new Customer();
customers.Add(dummyCustomer);

现在,去重构数据访问类,以使GetCustomers返回" IEnumerable <Customer>",然后看看会发生什么...

这里的问题是,在第一个示例中,我们明确表示了对GetCustomers方法的期望,也就是说,我们期望它返回的行为类似于列表。在第二个示例中,这种期望是隐式的,并且从代码中不会立即显而易见。

(对我而言)有趣的是,许多赞成变量的参数都说"我不在乎它返回的类型",但继续说"我只需要迭代它..."。 (因此它需要实现IEnumerable接口,这意味着类型确实很重要)。

回答

有时,编译器还可以比开发人员推断出"更好"的要求,至少是不了解他所使用的api要求的开发人员。

例如,当使用linq时:

例子1

Func<Person, bool> predicate = (i) => i.Id < 10;
IEnumerable<Person> result = table.Where(predicate);

例子2

var predicate = (Person i) => i.Id < 10;
var result = table.Where(predicate);

在上面的代码中,假设一个人使用Linq进行Nhibernate或者Linq进行SQL,示例1将
带回Person对象的整个结果集,然后在客户端上进行过滤。
但是,示例2将在服务器上进行查询(例如在带有SQL的Sql Server上),因为编译器足够聪明,可以确定Where函数应采用Expression>而不是Func。

由于返回了IEnumerable,因此示例1中的结果也无法在服务器上进一步查询,而在示例2中,如果结果应为IQueryable而不是IEnumerable,则编译器可以计算出结果

回答

我尽可能地使用var

本地变量的实际类型与代码的编写是否正确无关(即,良好的变量名称,注释,清晰的结构等)。

回答

在从事Java十年后,我在Cworld领域还很陌生。我最初的想法是"哦,不行!类型安全无济于事"。但是,我对var的了解越多,我就越喜欢它。

1)Var是与显式声明的类型一样安全的每一位。这全都与编译时语法糖有关。

2)遵循DRY的原理(请勿重复)。 DRY就是要避免冗余,并且在两侧都指定类型肯定是多余的。避免冗余只是为了使代码更易于更改。

3)至于知道确切的类型..好吧..我会说,我们总有一个总的想法,就是我们有一个整数,一个套接字,一些UI控件或者其他任何东西。 Intellisense将从这里指导我们。知道确切的类型通常并不重要。例如。我会说,我们有99%的时间都不关心给定变量是long还是int,float或者double。在最后1%的情况下(这确实很重要),只需将鼠标指针悬停在var关键字上方。

4)我已经看到了一个荒谬的论点,即现在我们需要回到1980年代的匈牙利疣,以区分变量类型。毕竟,这是蒂莫西·道尔顿(Timothy Dalton)扮演詹姆斯·邦德(James Bond)时代唯一告诉变量类型的方法。但是现在是2010年。我们已经学会了根据变量的用法和内容来命名变量,并让IDE指导它们的类型。只要继续这样做,var就不会伤害我们。

综上所述,var不是什么大问题,但这确实是一件好事,而且Java很快就会更好地复制它。所有反对的论点似乎都是基于IDE之前的谬论。我会毫不犹豫地使用它,我很高兴Rhelps能够这样做。

回答

使用LINQ时,使用var的另一个很好的理由是编译器可以进一步优化查询。

如果使用静态列表存储结果,它将在将其分配给列表的位置执行,但是使用var可以将原始查询与代码中的后续查询合并,从而对数据库进行更优化的查询。

我有一个示例,在该示例中,我在第一个查询中提取了一些数据,然后循环访问并请求更多数据以打印出表格。

LINQ将这些合并,以便第一个仅提取ID。

然后在循环中添加了一个我未在其中进行过的额外联接来获取原始文件中包含的数据。

经过测试,证明效率更高。

如果我们不使用" var",它将完全按照编写查询的方式进行查询。

回答

如果知道类型,请使用类型。
如果我们不知道类型,为什么不呢?
如果我们不知道类型,那可以-我们已经找到了唯一有效的用法。

很抱歉,但是如果我们能做的最好是"它使代码全部对齐",那不是一个很好的答案。寻找另一种格式化代码的方式。

回答

var是很好的方法,因为它遵循经典的DRY规则,当我们在声明变量的同一行中指定类型时,它尤其优雅。 (例如var city = new City())

回答

" var"是在C3.0和LINQ中为"匿名类型"引入的占位符。

这样,它允许编写LINQ查询以获取集合中较少数量的列。无需复制内存中的信息,只需加载完成我们需要完成的工作所需的内容。

使用var一点也不坏,因为它实际上不是类型,但是正如其他地方提到的那样,该类型的占位符必须在等式的右侧定义。然后,编译器将用类型本身替换关键字。

即使类型名称很长(即使使用IntelliSense),它也特别有用。只需编写var并实例化即可。以后将阅读代码的其他程序员将很容易理解我们在做什么。

就像使用

public object SomeObject { get; set; }

代替:

public object SomeObject {
    get {
        return _someObject;
    } 
    set {
        _someObject = value;
    }
}
private object _someObject;

每个人都知道属性的作用,每个人都知道var关键字的作用,并且这两个示例都倾向于通过使其更轻便来减轻可读性,并使程序员编写有效的代码更加愉快。

回答

"关于我的品味,你唯一能说的就是它是老式的,随着时间的流逝,你也将成为我的品味。" -托尔金。

回答

没错,但这可能是不合适的。有关示例,请参见所有其他响应。

var x = 5; (坏的)

var x = new SuperDooperClass(); (好的)

var x =从db中的t开始。选择new {Property1 = t.Field12}; (更好的)

回答

不要使用它,使代码不可读。

总是使用尽可能严格的输入方式,拐杖只会使生活陷入困境。

回答

埃里克的答案在这里...

C#中泛型类型的命名空间范围别名

相关的。

问题的部分原因是C#中没有强类型的别名。因此,许多开发人员将var用作部分代理。

回答

除了对可读性的关注外,使用" var"还有一个真正的问题。当用于定义在代码的后面分配给变量的变量时,如果用于初始化变量的表达式的类型更改为较窄的类型,则可能导致代码损坏。通常,重构方法以返回比以前窄的类型是安全的:用某些类" Foo"替换" Object"的返回类型。但是,如果存在根据该方法推断类型的变量,则更改返回类型将意味着可以再为该变量分配一个非Foo对象:

var x = getFoo(); // Originally declared to return Object
x = getNonFoo();

因此,在此示例中,更改getFoo的返回类型将使getNonFoo的赋值非法。

如果getFoo及其所有用途都在同一个项目中,这没什么大不了的,但是如果getFoo在供外部项目使用的库中,则我们不再可以确定缩小返回类型不会破坏某些用户代码,如果他们像这样使用'var'。

正是由于这个原因,当我们向Curl编程语言(在Curl中称为" def")添加类似的类型推断功能时,我们可以防止分配给使用此语法定义的变量。

回答

我只在很清楚看到使用哪种类型时才使用var。

例如,在这种情况下,我将使用var,因为我们可以立即看到x的类型为" MyClass":

var x = new MyClass();

在这种情况下,我不会使用var,因为我们必须将鼠标拖动到代码上,并查看工具提示以查看MyFunction返回的类型:

var x = MyClass.MyFunction();

特别是,在右边甚至不是方法,而只是值的情况下,我从不使用var:

var x = 5;

(因为编译器无法知道我是否需要字节,short,int或者其他任何内容)

回答

当然," int"很容易,但是当变量的类型为" IEnumerable <MyStupidLongNamedGenericClass <int,string >>"时,var使事情变得容易得多。

回答

好吧,这个观点在整个过程中都将得到认可,但是我会尽力提出自己的观点,尽管我认为我的观点太过复杂,以至于我们无论如何也不会从中得到很多。

首先是匿名类型,我们需要使用" var"关键字才能将具有匿名类型的对象分配为其类,这里没有太多讨论,需要" var"。

但是对于更简单的类型,我倾向于使用正确的类型,例如整型,长型,字符串型。主要是因为它有点像"懒惰的工具",我在这里看不到太多收获,很少有按键操作,而且以​​后可能会造成混乱,这是不值得的。尤其是浮点数的各种类型(浮点数,双精度数,十进制数)使我感到困惑,因为我不太喜欢我想在源代码中看到的字面量中的后缀。

话虽如此,如果类型更复杂和/或者在赋值的右侧被明确重复,我倾向于使用var alot。可以是List &lt;string>等,例如:

var list = new List<string>();

在这种情况下,我认为重复两次该类型是没有用的,尤其是当我们开始更改代码并且类型更改时,泛型类型可能变得越来越复杂,因此必须两次更改它们只是一种痛苦。但是,当然,如果我们希望针对IList &lt;string>进行编码,则必须显式命名该类型。

简而言之,我执行以下操作:

  • 当类型简短或者无法从上下文中读取时,显式命名类型
  • 在必须使用时使用var(duh)
  • 当var(在我看来)不会损害可读性时,请使其变懒

回答

我认为我们在问题中指出了var的主要问题:"我不必弄清楚类型"。正如其他人指出的那样,有一个地方可以使用var,但是如果我们不知道要处理的类型,那么很有可能在所有情况下都不会出现问题,但是那里有足够的气味,所以我们应该多疑。

回答

第一的。

var不是一种类型,也不是某些特殊功能(例如c4.0 dynamic)。这只是语法糖。我们要求编译器通过右侧表达式来推断类型。唯一必要的地方是匿名类型。

我不认为使用var既不是好事也不是坏事,它是编码风格。我个人不使用它,但我不介意其他团队成员使用它。

回答

如果有人因为不想"弄清楚类型"而使用" var"关键字,那肯定是错误的原因。关键字var不会创建具有动态类型的变量,编译器仍必须知道该类型。由于变量始终具有特定的类型,因此,如果可能的话,该类型也应在代码中显而易见。

例如,使用var关键字的充分理由如下:

  • 在需要的地方,即声明对匿名类型的引用。
  • 它使代码更具可读性,即删除重复的声明。

写出数据类型通常会使代码更易于遵循。它显示了我们正在使用的数据类型,因此我们不必通过先弄清楚代码的作用来弄清楚数据类型。

回答

var不错。记住这一点。 var不错。重复。 var不错。记住这一点。 var不错。重复。

如果编译器足够聪明,可以从上下文中找出类型,那么我们也是如此。我们不必在声明时就将其写下来。而智能感知使这一点变得不必要了。

var不错。记住这一点。 var不错。重复。 var不错。记住这一点。 var不错。重复。

回答

在我看来,Var很好。这样键入的任何变量仍然是强类型,但是它是从定义它的赋值的右侧获取其类型的。因为类型信息在右侧可用,所以在大多数情况下,也不必在左侧输入类型信息,这是不必要的且过于冗长。我认为这可以显着提高可读性,而不会降低类型安全性。

从我的角度来看,从可读性的角度来看,对变量和方法使用良好的命名约定比显式类型信息更为重要。如果需要类型信息,则可以始终将鼠标悬停在变量上(在VS中)并获取它。通常,尽管如此,对于读者而言,显式类型信息不是必需的。对于开发人员,无论如何声明变量,在VS中我们仍然可以获得Intellisense。综上所述,在某些情况下仍然有必要明确声明类型-也许我们有一个返回List &lt;T>的方法,但是我们想将其视为`IEnumerable <T>以方法。为确保我们使用的是接口,声明接口类型的变量可以使它明确。或者,也许我们想声明一个没有初始值的变量-因为它会根据某种条件立即获得一个值。在这种情况下,我们需要输入类型。如果类型信息有用或者必要,请继续使用它。不过,我觉得通常没有必要,而且在大多数情况下,没有它,代码也更容易阅读。

回答

我认为我们可能误解了C#中var的用法。与VB variant类型不同,它仍然是强类型,因此无论是否使用它都不会影响性能。

由于对最终编译的代码没有影响,因此它实际上是设计师的选择。我个人不使用它,因为我发现使用已定义的完整类型更容易阅读代码,但是我可以想象几年后会以与匈牙利表示法相同的方式查看完整类型声明默认情况下,打字不会对智能感知给我们的信息带来任何实际好处。

回答

我认为,大量使用var是没有问题的。它不是自己的类型(我们仍在使用静态类型)。相反,它只是节省时间,可以让编译器弄清楚该怎么做。

像其他任何时间节省程序(例如自动属性)一样,在任何地方都使用它之前,先了解它是什么以及它如何工作是一个好主意。

回答

这些都不是绝对正确的。 var对可读性既有正面影响也有负面影响。我认为,当以下任一情况成立时,应使用" var":

  • 该类型是匿名的(好吧,我们在这里别无选择,因为在这种情况下必须为var)
  • 根据分配的表达式,该类型是显而易见的(即var foo = new TypeWithAReallyLongNameTheresNoSenseRepeating())

var是句法糖,对性能没有影响;编译器会推断出类型并在将其编译为IL后对其进行定义;实际上没有任何动态。

回答

这还不错,更多的是风格,这往往是主观的。当我们使用var或者不使用var时,它可能会增加不一致之处。

另一个值得关注的情况是,在下面的调用中,我们不能仅通过查看CallMe返回的类型的代码来判断:

var variable = CallMe();

那是我对var的主要抱怨。

当我在方法中声明匿名委托时,我使用var,以某种方式var看起来比使用Func更干净。考虑以下代码:

var callback = new Func<IntPtr, bool>(delegate(IntPtr hWnd) {
   ...
});

编辑:根据朱利安的输入更新了最后一个代码示例

回答

由于冗余原因将其删除。

vars仍被初始化为编译器只是从上下文中推断出的正确变量类型。正如我们所暗示的,var使我们能够存储对匿名类实例的引用,但它也使更改代码变得更加容易。例如:

// If you change ItemLibrary to use int, you need to update this call
byte totalItemCount = ItemLibrary.GetItemCount();

// If GetItemCount changes, I don't have to update this statement.
var totalItemCount = ItemLibrary.GetItemCount();

是的,如果很难根据变量的名称和用途来确定其类型,则一定要明确声明其类型。

回答

Var根本不像变体。变量仍然是强类型的,只是我们没有按键来获取它。我们可以将鼠标悬停在Visual Studio中以查看类型。如果我们正在阅读印刷代码,则可能需要三思而后行才能弄清类型。但是只有一行声明它,许多行使用它,因此给事情起个像样的名字仍然是使代码易于理解的最佳方法。

使用Intellisense懒吗?它的输入比全名要少。还是有一些工作量少但不值得批评的事情?我认为有,而var是其中之一。

回答

令人惊讶的是,到目前为止还没有注意到这一点,但是将var用作foreach循环变量是常识。

如果改为指定特定类型,则冒着编译器将运行时强制转换静默插入程序的风险!

foreach (Derived d in listOfBase)
{

以上将编译。但是编译器会从"基础"向"衍生"插入下调。因此,如果列表中的任何内容在运行时都不是"派生的",则存在无效的强制转换异常。类型安全性受到损害。看不见的演员很可怕。

排除这种情况的唯一方法是使用var,因此编译器根据列表的静态类型确定循环变量的类型。

回答

我们可以让编译器(以及接下来维护代码的人员)从初始化程序赋值的右侧推断类型。如果可以进行这种推断,则编译器可以做到这一点,从而节省了键入工作。

如果对于那个可怜的家伙来说推断很容易,那么我们就不会受到任何伤害。如果推论很难,那么就使代码难于维护,因此通常
我不会的

最后,如果我们打算将类型指定为特殊类型,并且初始值设定项表达式实际上具有不同的类型,则使用var意味着我们将更难找到诱发的错误。通过显式告诉编译器我们打算将类型指定为什么,当类型不是该类型时,我们将得到立即诊断。通过拖延类型声明并使用" var",将不会在初始化时出现错误。取而代之的是,在使用var表达式分配的标识符的某些表达式中会出现类型错误,并且很难理解为什么。

因此,道德上要谨慎使用var;我们通常不会为自己或者下游维护者带来很多好处。并希望他以同样的方式进行推理,这样我们就不会因为他认为使用var很容易而猜测他的意图了。在对使用寿命长的系统进行编码时,优化键入的数量是一个错误。

回答

使用var代替显式类型使重构更加容易(因此我必须与之前的声明相矛盾,后者意味着它没有什么作用,或者纯粹是"语法糖")。

我们可以更改方法的返回类型,而无需更改调用此方法的每个文件。想象

...
List<MyClass> SomeMethod() { ... }
...

...
IList<MyClass> list = obj.SomeMethod();
foreach (MyClass c in list)
  System.Console.WriteLine(c.ToString());
...

如果要重构SomeMethod()以返回IEnumerable &lt;MySecondClass>,则必须在使用该方法的每个位置更改变量声明(也在" foreach"内部)。

如果你写

...
var list = obj.SomeMethod();
foreach (var element in list)
  System.Console.WriteLine(element.ToString());
...

相反,我们不必更改它。

回答

我们最可能需要的时间是匿名类型(要求100%);但这也避免了琐碎的重复,国际海事组织使这一界限更加清晰。我不需要两次查看类型就可以进行简单的初始化。

例如:

Dictionary<string, List<SomeComplexType<int>>> data = new Dictionary<string, List<SomeComplexType<int>>>();

(请不要在上面编辑hscroll,这足以证明这一点!!!)

vs:

var data = new Dictionary<string, List<SomeComplexType<int>>>();

但是,在某些情况下,这会产生误导,并可能导致错误。如果原始变量和初始化类型不相同,请小心使用" var"。例如:

static void DoSomething(IFoo foo) {Console.WriteLine("working happily") }
static void DoSomething(Foo foo) {Console.WriteLine("formatting hard disk...");}

// this working code...
IFoo oldCode = new Foo();
DoSomething(oldCode);
// ...is **very** different to this code
var newCode = new Foo();
DoSomething(newCode);

回答

我们不必写出类型名称,而且由于在编译时已解析类型,因此性能也不低。

回答

在大多数情况下,想象起来更简单

var sb = new StringBuilder();

代替:

StringBuilder sb = new StringBuilder();

有时它是必需的,例如:匿名类型,如。

var stuff = new { Name = "Me", Age = 20 };

尽管它使代码的可读性和可维护性较差,但我个人还是喜欢使用它。

回答

纯粹是为了方便。编译器将推断类型(基于右侧表达式的类型)

回答

从Essential LINQ:

除非绝对必要,否则最好不要显式声明范围变量的类型。例如,以下代码可以干净地编译,但是编译器可以在没有正式声明的情况下推断出类型:

List<string> list = new List<string> { "LINQ", "query", "adventure" };
var query = from string word in list
      where word.Contains("r")
      orderby word ascending
      select word;

明确声明范围变量的类型会强制对LINQ Cast运算符进行幕后调用。此调用可能会产生意想不到的后果,并可能会损害性能。如果我们在使用LINQ查询时遇到性能问题,则可以使用此处所示的演员表开始查找罪魁祸首。 (此规则的一个例外是,当我们使用非通用Enumerable时,在这种情况下,我们应该使用强制类型转换。)

回答

边缘案例之间肯定会有分歧,但是我可以告诉我们我的个人准则。

当我决定使用var时,我会看这些标准:

  • 从上下文来看,变量的类型[对人类而言]是显而易见的
  • 变量的确切类型与[人类]没有特别的关系[例如,我们可以找出算法在做什么,而无需关心我们使用的是哪种容器]
  • 类型名称很长,会打乱代码的可读性(提示:通常是通用的)

相反,这些情况会迫使我不要使用var

  • 类型名称相对简短且易于阅读(提示:通常不是通用名称)
  • 从初始化程序的名称来看,类型不明显
  • 确切的类型对于理解代码/算法非常重要
  • 在类层次结构上,当人们无法轻易分辨出正在使用哪个层次结构时

最后,我绝不会将var用于本机值类型或者对应的null类型(null,nullable <>)(int,decimal,string,decimal ...)。有一个隐含的假设,即如果我们使用var,则必须有一个"原因"。

这些都是准则。我们还应该考虑同事的经验和技能,算法的复杂性,变量的寿命/范围等。

大多数时候,没有完美的正确答案。或者,这并不重要。

[编辑:删除了重复的项目符号]

回答

我认为var并不是一个可怕的语言功能,因为我每天都使用Jeff Yates描述的代码来使用它。实际上,几乎每次我使用var都是因为泛型可以编写一些非常冗长的代码。我住的是冗长的代码,但泛型使它走得太远了。

就是说,我(显然是……)认为var可以接受滥用了。如果在使用杂乱无章的方法的情况下,代码达到20行以上,我们将很快使维护成为一场噩梦。另外,教程中的var非常难以理解,在我的书中通常是一个很大的禁忌。

另一方面,var是一项"简单"功能,新程序员将开始使用并喜欢它。然后,在几分钟/几小时/几天之内,当他们开始达到极限时,就遇到了巨大的障碍。 "为什么我不能从函数返回var?"这样的问题。另外,将伪动态类型添加到强类型语言中很容易使新开发人员陷入困境。从长远来看,我认为var关键字实际上会让新手程序员感到有魅力。

就是说,作为一名经验丰富的程序员,我确实使用var,主要是在处理泛型(以及显然是匿名类型)时使用。我确实同意我的说法,但我确实相信var将是滥用最严重的功能之一。

回答

在测试过程中很多次,我发现自己有这样的代码:

var something = myObject.SomeProperty.SomeOtherThing.CallMethod();
Console.WriteLine(something);

现在,有时候,我想看看SomeOtherThing本身包含的内容,SomeOtherThing与CallMethod()返回的类型不同。由于我使用的是var,因此只需更改以下内容:

var something = myObject.SomeProperty.SomeOtherThing.CallMethod();

对此:

var something = myObject.SomeProperty.SomeOtherThing;

没有var,我也必须不断更改左侧的声明类型。我知道这是次要的,但是非常方便。

回答

根据我昨天编写的代码,它肯定可以使事情变得更简单:

var content  = new Queue<Pair<Regex, Func<string, bool>>>();
...
foreach (var entry in content) { ... }

如果没有var,这将非常冗长。

附录:花一点时间使用具有实类型推断的语言(例如F#)将显示出正确的表达式类型的良好编译器。当然,这意味着我倾向于尽可能多地使用" var",并且现在使用显式类型表明变量不是初始化表达式的类型。

回答

当我们不想重复自己时,var很棒。例如,昨天我需要一个与此类似的数据结构。我们喜欢哪种代表?

Dictionary<string, Dictionary<string, List<MyNewType>>> collection = new Dictionary<string, Dictionary<string, List<MyNewType>>>();

或者

var collection = new Dictionary<string, Dictionary<string, List<MyNewType>>>();

请注意,在此示例中,使用var几乎没有引起歧义。但是,有时候这不是一个好主意。例如,如果我按照以下方式使用var

var value= 5;

当我可以写实类型并消除应该如何表示" 5"的任何歧义时。

double value = 5;

回答

鉴于Intellisense的强大功能,我不确定var是否比在类中具有成员变量或者在可见屏幕区域之外定义的方法中的局部变量难读。

如果我们有一行代码,例如

IDictionary<BigClassName, SomeOtherBigClassName> nameDictionary = new Dictionary<BigClassName, SomeOtherBigClassName>();

比:更容易或者更难阅读:

var nameDictionary = new Dictionary<BigClassName, SomeOtherBigClassName>();

回答

它可以使代码更简单,更短,尤其是对于复杂的泛型类型和委托。

而且,它使变量类型更易于更改。

回答

我想这取决于观点。我个人从来没有因为var" misuse"而理解任何代码的困难,我的同事和我经常使用它。 (我同意Intellisense在这方面提供了巨大的帮助。)我欢迎它作为消除重复性废料的一种方式。

毕竟,如果语句像

var index = 5; // this is supposed to be bad

var firstEligibleObject = FetchSomething(); // oh no what type is it
                                            // i am going to die if i don't know

真的无法应对,没有人会使用动态类型的语言。

回答

取决于,以某种方式使代码看起来更``干净'',但同意它使代码更难以阅读...

回答

当我们将鼠标悬停在" var"上时,带有Resharper 4.1的VS2008在工具提示中具有正确的键入内容,因此我认为当我们查找类的所有用法时,它应该能够找到该提示。

尚未测试它是否可以做到这一点。

回答

一个很好的论点,为什么不应该将vars用作单纯的"键入快捷方式",而应该将其用于主要设计用于的场景:Resharper(至少v4.5)如果将类型表示为a,则无法找到该类型的用法变种在重构或者分析源代码时,这可能是一个真正的问题。

回答

在讨论中迟到了,但我想补充一下。

对于所有反对类型推断的人(因为这是我们在这里真正谈论的内容),lambda表达式又如何呢?如果我们坚持始终明确声明类型(匿名类型除外),那么对lambda怎么办? "不要让我使用鼠标悬停"参数如何应用于var但不适用于lambda?

更新

我刚刚想到了一个反对'var'的论点,但我认为没有人提到过,这是说它"破坏"了"查找所有引用",这可能意味着(例如)如果我们正在检查用法重构前,我们会错过通过var使用该类的所有地方。

回答

对于那些认为var可以节省时间的拥护者,键入该键所花费的时间更少:

StringBuilder sb = new StringBuilder();

var sb = new StringBuilder();

如果我们不相信我,请数一数。

19比21

我会解释是否必须这样做,但请尝试一下...(取决于智能感知的当前状态,我们可能需要为每个输入多输入几对)

我们可以想到的每种类型都是如此!

我个人的感觉是,除非未知类型,否则永远不要使用var,因为它会减少代码中的识别可读性。识别该类型所需的时间比整条线要长。懂机器代码和位的老计时器完全知道我在说什么。大脑并行处理,当我们使用var时,我们强制其序列化其输入。为什么会有人想让自己的大脑更努力地工作?那就是计算机的用途。