在C#中使用var关键字


406

与同事讨论了在C#3中使用'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 确实保持强类型,但是问题实际上是类型在定义时不立即变得危险吗?当重载意味着在无意中将错误类型传递给方法时,可能不会发出编译器错误,这种情况会放大。


68
使用var很好,但是“我不必弄清楚类型”似乎是使用它的一个非常不好的理由...您应该知道类型是什么,var只是避免键入它的快捷方式
托马斯·列维斯克

53
var i = 0;==失败!var c = new CrazyFrigginLongClassName();==赢了!
dotjoe 2010年

6
“ Var还使我想起了VB / VBA变体类型。它也有它的位置。我回顾了(从很多年前开始)它的用法不如所期望的类型,而且相当耗资源。” <-表明这是一个诱人的问题,因为C#的'var'类型与VB / VBA变体类型无关。
user7116'5

20
var readabilityBeDamned = true;
spoulson

9
这里说明的所有示例的问题在于,我们只看一行代码。当我看到一行又一行的“ var”声明时,它变得一发不可收拾。可读性是主观的,但是我发现var被滥用的程度远远超过了应有的使用程度。
2011年

Answers:


293

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

var orders = cust.Orders;

我不在乎Customer.Orders是IEnumerable<Order>ObservableCollection<Order>或者BindingList<Order>-我要的是保持该列表在内存中遍历,或以后得到了数什么的。

将以上声明与:

ObservableCollection<Order> orders = cust.Orders;

对我来说,类型名称只是噪音。如果我返回并决定更改Customer.Orders的顺序(例如从ObservableCollection<Order>to IList<Order>),那么我也需要更改该声明-如果我在第一个中使用var则不必这样做地点。


48
当我阅读代码时,我喜欢在我面前有显式类型。我如何知道这里没有类型的“ cust.Orders”?是的,我可以将鼠标悬停以进行查找,但是为什么我必须这样做?:)
乔恩·塔卡伯里

77
但问题是,总体而言这并不重要。提供的cust.Orders是您可以枚举的内容(例如foreach over),那么它是什么类型都没有关系。额外的代码只会妨碍您阅读意图。
马特·汉密尔顿,

67
但是,如果您仅要求cust.Orders是“您可以枚举的东西”,那么是否没有将其声明为IEnumerable <Order>来使该要求明确而又清晰?将其声明为var意味着您实际上失去了该要求。
GrahamS

5
@jon和IEnumerbal订单= cust.Orders foreach(订单中的var订单)将如何起作用?IEnumerable所说的唯一一句话是,您可以将其放在foreach中,但您已经从下面的一行中知道了
Rune FS 2010年

18
“ IEnumerable唯一可以说的就是可以将它放到foreach中”-它也表达了唯一可以枚举的意图。使用var可为具体集合类型的公共成员提供访问权限并提供智能感知。

167

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

诚然,这可能意味着我们不清楚要处理的是哪种类型。所以呢?这实际上是分离设计的重点。在处理接口时,您对变量的类型毫无兴趣。var借此更进一步,真实的,但我认为争论依然从一个可读性一点是相同的:程序员不应实际感兴趣的变量的类型,而是在什么变数。这就是Microsoft为何也将类型推断称为“鸭子类型”的原因。

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

如果我使用的是var声明的变量,并且对该变量的用途感到困惑,则我的代码根本存在问题。var不是原因,只会使症状可见。不要怪信使。

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

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


14
在任何体面的IDE中,您都不使用文本搜索来获取类的用法,而是让IDE根据其解析树来执行此操作,否则它会标识对象的类型。由于我们在谈论静态类型,因此它将找到除匿名类型之外的所有内容。
垃圾工

6
我不想继承10万行源代码,而没有任何文档,也没有广泛使用var。特别是当您将var与不太有用的变量名结合在一起时。在生产代码中说明一个点(或处理匿名类型)时,我可以看到它很有帮助?
乳木果

7
Arnshea:好了,您已经指出了真正的问题:无用的变量名和缺少的文档。我真的看不出是什么var导致了混乱。当然,在某些情况下,强调变量的类型/大小非常重要(例如,低级位操作)。很好:没有人声称var应该专门使用它。规则很简单:如果确实引起混乱,请不要使用它。
康拉德·鲁道夫

17
我见过的每个与var相反的示例都假定程序员将使用无意义的变量名。但这也许就是为什么var 优于显式指定类型的原因:它迫使程序员提供好的变量名。
Ryan Lundy

16
微软还称类型推断为“鸭式打字”。-真的吗?我会感到震惊...
2009年

118

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

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


3
我总体上同意。我认为这里的重点是确定意图是否明确。如果团队中的大多数开发人员不清楚,那么这是有害的,没有帮助。话虽如此,我个人还是对此的忠实拥护者,但是当团队中的其他开发人员无法确定我的意图时,我不得不束手无策。去搞清楚。
史蒂夫·布劳拉德

3
嗯,我发现当类型在左侧时更容易阅读。使用ReSharper,无论如何我都不必在右侧重新输入类型,因此它不会打扰我。
BlueRaja-Danny Pflughoeft 2010年

1
@BlueRaja-我发现使用好的变量名通常可以消除为理解而实际使用的类型的麻烦。仍然可以在“ var”定义的变量上使用Intellisense,因此在编码时我不需要知道类型来选择方法/属性。
tvanfosson

2
与其说何时编码,不如说当您必须阅读代码时。
BlueRaja-Danny Pflughoeft,2010年

1
然后,我必须站得住脚,我需要好的方法和变量名以及对要操作的类型的理解,以便能够正确理解我正在阅读的代码。我认为您是对的,尽管这是更大问题的征兆。信任之一。要确保代码正在执行其看起来正在执行的操作,您需要确定所使用的类型。
AnthonyWJones

91

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

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

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


1
尽管在第二种情况下我有很长的限制,但在这两种情况上都应达成共识,如果一个类型太长,则通常是带有大量嵌套泛型参数的泛型,在这种情况下,强类型化的“ ShortType等效于TypeWithAReallyLongNameTheresNoSenseRepeating”更有意义
离子Todirel'5

12
我不希望发动宗教战争,但我个人倾向于不同意离子。我更喜欢一个非常长但非常精确的类型名称(ala叔叔鲍勃·马丁叔叔),而不是一个简短且可能含糊的简短类型名称。我还要补充一点,我也不同意人为地夸大名称的长度。如果5个字符创建了一个简洁的名字清楚地表明意图,然后用5而不是25
史蒂夫Brouillard

2
@史蒂夫:我必须同意你的观点。创建“短类型”(我认为您是指仅出于缩短名称的目的而从特定的泛型类型继承)不是一个好习惯;它将要求您复制并通过泛型类型传递任何构造函数,并阻止您将继承自泛型类型的其他类型传递给函数。您正在使用继承typedef,而不是继承。
亚当·罗宾逊

7
var当类型明显时使用?也许,但是真正的收获是当类型无关紧要时。如果您正在做类似的var customers = whatever; var query = from c in customers select stuff事情,那么“客户”的确切类型是什么都没关系。很明显,如何使用它就足够了。而且,如果实际类型繁琐,则有必要加以抑制。
Joren 2010年

2
@Kristoffer:我可以理解要消除标记的混乱,但是将它们包装到一个类中不是(IMO)可接受的替代方法,因为这样可以避免该泛型的任何其他(合法)子类成为有效参数。我宁愿using ShortType = LongGenericType<A,B,C>在文件顶部使用指令,因为它具有相同的可读性,不需要您重新创建构造函数,也不会从子类中排除子类。
亚当·罗宾逊

68

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

为什么var引入关键字?

有两个原因,一个是今天存在的原因,一个是将在3.0中出现。

第一个原因是由于所有冗余,此代码非常丑陋:

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

这是一个简单的例子–我写得更糟。每当您被迫两次键入完全相同的内容时,这就是我们可以删除的多余内容。写起来好多了

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

并让编译器根据分配确定类型。

其次,C#3.0引入了匿名类型。由于匿名类型在定义上没有名称,因此,如果变量的类型为匿名,则您需要能够从初始化表达式中推断出变量的类型。

强调我的。整篇文章,C#3.0仍然是静态类型,老实说!,随后的系列也相当不错。

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


我觉得利珀特的论点很奇怪。没有人键入第二个类的名称,他们让Intellisense为其编写代码,但是随后他转身声称var更好,因为编译器/ Intellisense可以解决这个问题。您不能同时拥有它!
戴夫

5
C#团队不控制智能,而是控制编译器。无论如何,这不是主要问题。我不认为var会在单独保存类型方面取得100分。
垃圾工

@Dustman:var根本不保存输入。它使您写得更多!
霹雳霹雳州

53

我认为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。


6
好吧,唯一的错误是“ var f =(float)3;” 则应为“ var f = 3f”或“ var f = 3.0(导致单精度错误)”。
MichaelGG

3
是的,3f或3.0是必经之路!我们var疯子必须团结在一起!
马特·汉密尔顿

27
在第一个示例中,真正的问题是“列表”,而不是“ c”。“清单”是什么?“列表”应重命名为“客户”或“ customersWhoOweMoney”或“ currentCustomers”,或更具描述性的名称。并且一旦有了它,“ c”就可以保持原样,因为您已经知道它所包含的内容。
Ryan Lundy

4
嗨,马特!我的名字叫肯尼,我是一名varaddict。
肯尼2010年

var MattHamil =“卢克·天行者”; //
从中

40

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

对我来说,这排除了编译器“知道”变量类型的说法-当然,您不能第一次编写无效的代码,因为编译器会停止编译代码,但是当下一个开发人员正在读取代码时在6个月的时间内,他们需要能够推断出变量在做什么,正确或不正确,并迅速找出问题的原因。

从而,

var something = SomeMethod();

已被我们的编码标准所禁止,但我们的团队鼓励以下内容,因为它提高了可读性:

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

4
我发现(“为人而不是机器的代码”)是一个很好的指南-遵循它可以导致更好的代码并有助于避免过早的优化。
塔纳托斯

3
我没有得到var list = new KeyValuePair <string,double>?对我来说,清单上可以包含的内容不止于此。
TTT

“为人而不是机器的代码”-阿们。
user1068352 2012年

39

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

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

var variable = CallMe();

那是我对var的主要抱怨。

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

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

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


3
但是,您真的需要知道那一行的类型吗?您知道CallMe返回了一些信息。知道variable是否创建了名为的局部变量还不够吗?除非你扩大自己的榜样,否则这不是一个很坚实的抱怨。
兰道夫

2
这不是关于不冗长,而是关于不要让编译器为您做语法糖。考虑一下:var getter ...,现在是Func <object> getter ...,第二个您知道您不必提供任何参数及其返回的内容。您从一开始就知道“该做什么”,并且在设计某些东西或进行重构时可以更快地做出决策。掌握所有信息比其他几个字符更为重要。只有在使用大量代码时,才能体会到这一点。
艾迪·托迪雷尔

2
既然我们都在谈论Visual Studio,那么将鼠标悬停在变量上一秒钟,然后看看它是什么类型有什么大不了的?无论如何,比执行声明要好得多。
Rubys 2010年

3
通用变量和函数名(variableCallMe)做坏榜样。但是,如果CallMe()是某种“电话应用程序”中的功能,那么var call = CallMe(); .... call.HangUp();它将更加有意义。
DankoDurbić2010年

3
@Randolpho:“将鼠标悬停在变量上一秒钟,然后看看它是什么类型,这有什么大不了的?” 它增加了维护的时间...再加上一秒钟只是悬停时间,而不是计算键盘到鼠标的上下文切换。我不认识你,但我有最后期限。每次我必须将鼠标悬停在变量上以查明它是什么类型时,我本该花更多的时间解决问题。
Powerlord 2010年

36

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

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


6
+1,只有要注意的人与var无关Variant
user7116 2010年

27

您最可能需要的时间是匿名类型(要求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);

1
(有关信息,在任何隐式类型转换的情况下,您都可能遇到类似的问题)
Marc Gravell

1
对于您不想在同一行中看到两次的部分,表示不同意。将来有可能您不是在声明之后直接创建变量(例如,在定义下方的if中),而可能不是直接弄清类型是什么。大多数开发人员习惯于直接在行的开头看到类型,尤其是在复杂的代码中,您不想使阅读代码变得更加困难。
Gertjan

@TheVillageIdiot-我回滚了您的编辑,因为在这种情况下,hscroll与点有关;-p
Marc Gravell

2
@Gertjan-我的大脑有限;如果是复杂的,我希望看到它两次,不得不开始比较(接口/混凝土/等)。我很高兴看到它一次,并认为“键入其中之一”。
马克·格雷夫

17

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

您不能为此依赖鼠标悬停。


17
您为什么在纸上审查代码?想想树木!;)
垃圾工

8
您可以在不使用var的情况下遇到相同的问题。问题不在于var。问题是变量名错误。如果可以选择变量名,则使用var无关紧要。
Ryan Lundy

我的团队中有一个人检查他自己的代码,并通过打印他的代码来查找错误。他的墙被代码覆盖。我曾经走进去,他的整个大白板都覆盖着他的一次调试练习。大概是10000 LOC
哔哔声,

除非您返回类型是名称一部分的匈牙利符号,否则仅变量名称并不能解决问题。
凯文·盖尔

17

我没什么大不了的..

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的目的。


“某物”的类型对于编译器是非常清楚的,在内部,“ var”被设置为“ someMethod”的返回类型,这对于编译器是清楚的,但对于从事该项目的开发人员而言可能不是清楚的。Boo很快就在我身上成长。
stephenbayer

不,v = List<somethinglongtypename>();甚至没有更好。重要的是要区分引入新变量和分配给现有变量。
HighCommander4

好吧,如果您在当前作用域中之前已分配给“ v”,那么它将分配给现有的。否则,将其分配给新变量“ v”。简单。
Frep D-Oronge

17

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

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

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

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


11

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

如果您有一行代码,例如

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

比:更容易或更难阅读:

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

我实际上并没有考虑过这一点,从另一个问题来看,这似乎是另一个时间使用它的强项。
Finglas

这基本上是他们实现它的唯一原因(除了能够声明匿名类型之外,他们还可以使“ var”成为仅适用于匿名类型的特殊关键字。)
mqp

10

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

如果你某种类型的东西,那么您应该使用它-而不是简单的懒惰(而不是通常鼓励的创造性懒惰-优秀的程序员经常努力工作以变得懒惰,可以被认为是事物的来源)。

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

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

我怀疑这将要运行(-:

墨菲


10

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


2
为此+1。 intvs var是值得争论的事情,但是多个嵌套的泛型类型让人var赞叹不已。在此反复使用类型名称确实会破坏代码的可读性。
克里斯·法默

这绝对是使用它的错误原因。如果您的代码使用嵌套的泛型类型,则应为其派生一个特定的命名类。例如:class IntStringEnumerator : IEnumerable<MyStupidLongNamedGenericClass<int, string>>然后使用新名称。这样可以清理代码并更好地描述类型。
xxbbcc 2012年

好的,但是我的例子只是夸张。IntStringEnumerator i = new IntStringEnumerator()仍然打字太多。
Blorgbeard在2012年

9

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


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

MyObject m = new();

或者,如果您要传递参数:

人p = new(“ FirstName”,“ LastName);

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

最后,它并不是要减少冗余。不要误会我的意思,“ var”在C#中对于匿名类型/投影非常重要,但是当您混淆类型时,此处的用法就很遥远了(我已经说了很长时间了)正在被使用。不得不多次键入两次,而将其声明为零次则太少了。

Nicholas Paldino .NET / C#MVP,2008年6月20日上午08:00


我猜想,如果您主要关心的是不必键入太多内容-那么没有任何论点会影响您使用它。

如果你只打算永远是谁看着你的代码,那么谁在乎的人?否则,在这种情况下:

var people = Managers.People

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

var fc = Factory.Run();

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

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


4
上面的示例不是不使用var的论点;它们是使用好的描述性变量名的一个论据。如果您有[bool fc = Factory.Run();]而不是[var fc = Factory.Run();],那么代码将变得不那么清晰。
Ryan Lundy

9

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

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

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

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

如果您想重构SomeMethod()以返回IEnumerable<MySecondClass>,则必须更改变量声明(也在foreach在使用该方法的每个位置)。

如果你写

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

相反,您不必更改它。


同意-想知道为什么在受欢迎的回答中没有像其他一些更主观的专业人士那样吹捧这种很好的副作用。
fieldingmellish

今天对我来说太厉害了。我有一个工厂类,它返回MainMenu类的距离。今天,我创建了具有MainMenu相同界面的MainMenu2。更改后,我的所有应用代码都保持不变!
Marco Staffoli,2010年

8

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

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


2
您说这很有趣,因为var可以使重构更简单。如果您使用过var,则不必。现在您可以始终依赖IDE的重构工具,但是您知道,您也可以始终依赖IDE的类型:)
Fred

8

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

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

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

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


7

IEnumerable<int>和之间进行比较时,IEnumerable<double>您不必担心-如果您输入错误的类型,您的代码将始终无法编译。

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

Var Linq绝对需要:

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<'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
}

C#编译器非常聪明-如果属性匹配,则分别生成的匿名类型将具有相同的生成类型。

除此之外,只要您具有智能,就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;

IQueriable<T>在迭代之前摆脱掉: anonEnumeration.ToList();
David Diez

@DavidDiez你可以改写吗?你的说法没有道理。我的代码段均未引用IQueryable.ToList()
Keith 2013年

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 };不返回IQueriable<T>
David Diez 2013年

1
@DavidDiez取决于AllPosts()返回的内容- 询问者所指的是,List<T>所以我认为是。在这种情况下,结果anonEnumeration将是类型IEnumerable<'a>。现在,如果AllPosts()回报率IQueryable<T>不是那么anonEnumeration将成为IQueryable<'a>(注意没有i在可查询的) -然而,在这种情况下,我的代码仍然工作,因为IQueryable<T>工具IEnumerable<T>。关于它们之间的区别,这里有很多更好的Q&A-在这里我的情况'a是匿名的,var允许您将其分配给静态类型的变量。
Keith 2013年

哦,我明白了,谢谢您的解释:)我的评论是因为迭代an IQueryable<T>不是一个好习惯,因为在每次迭代中,您都在DB中编写一条read语句。一定要*.ToList() IQueryable<T>在迭代之前将它们设置为
David Diez,2013年

7

我想这取决于您的观点。我个人从来没有因为var“滥用”而理解一段代码的困难,我的同事和我经常使用它。(我同意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

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


大概在.Net 4中动态类型很常见的地方,这将变得更加重要吗?
科林·戴斯蒙德2009年

2
相反,如果您现在对“ var”感到困惑,那么我希望您还会对“动态”感到困惑。上帝禁止任何人声明动态,然后使用“ var”进行引用:)
mqp

我的意思是动态d = 52;var x = d; 应该没问题的
mqp

7

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

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

var x = new MyClass();

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

var x = MyClass.MyFunction();

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

var x = 5;

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


如果右侧不够清晰,无法证明使用var,则var不是问题所在:右侧就是问题。描述性不够Customer c = GetContext()仍然不清楚,没有比使用更好var
JulianR

6

对我而言,对var.NET 的反感说明了.NET中双语的重要性。对于也完成了VB .NET的C#程序员而言,的优势var在直观上显而易见。标准的C#声明:

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<string>,而不是一个List<string>?好吧,在VB .NET中,这意味着您必须执行以下操作:

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

就像您必须使用C#一样,并且显然不能var用于:

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

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


1
有趣的是,您提到双语会促进var的使用。我对var关键字的反对直接源于我对javascript的熟练程度!:)
Urig

varC#var中的JavaScript 与JavaScript 没有任何关系。一个var在C#-declared变量是强类型。
瑞安·伦迪

6

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

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

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

我不介意动态打字,也不介意隐式打字-使用为他们设计的语言。我很喜欢Python。但是C#被设计为静态显式类型的语言,因此它应该保持不变。打破匿名类型的规则已经很糟糕了。我不满意让别人更进一步,打破语言的习语。既然精灵已经从瓶子里拿出来了,就永远不会再回来了。C#会陷入困境。不好。


7
哇。到目前为止,无视此线程中提出的所有论点,并重新设置整个讨论是一个很大的成就。
Konrad Rudolph

这100%描述了我对“ var”的感觉,特别是从获取他人代码的角度来看。如果无所不在,使用var可以从根本上改变当前的任务。+1
西蒙(Simon)

6

在测试中很多时间,我发现自己有这样的代码:

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,我也必须不断更改左侧的声明类型。我知道它很小,但是非常方便。


6

对于那些认为var可以节省时间的发烧友来说,键入它所需的击键次数更少:

StringBuilder sb = new StringBuilder();

var sb = new StringBuilder();

如果你不相信我,请数数。

19比21

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

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

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


我发现stringBuilder sb = new StringBuilder()的重复很杂乱,无法清晰识别。这是额外的噪音。问题是,确定什么构成和不构成理解某些代码的额外智力工作非常主观!
ljs 2010年

“除非类型未知,否则永远不要使用var ...”-您始终可以知道类型,编译器也一样。这不是动态类型,它只是让编译器为您确定类型。但是类型永远不会是未知的。
加百利·麦格纳

5

我分裂VAR遍布的地方,我唯一值得商榷的地方是内部短路类型,例如我喜欢int i = 3;var i = 3;


5

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

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

没有的话,这将是非常冗长的var

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


是的,编译器比我们更聪明,克服它!
Benjol

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.