在与同事讨论了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(var item in someList){//…}相当于。

这里有一个关于类型安全的真正问题——例如,如果我们将该查询的结果放在一个接受IEnumerable<int>和IEnumerable<double>的重载方法中,调用者可能会无意中传入错误的类型。

Var确实保持强类型,但问题是,在定义中不立即显示类型是否危险,当重载意味着当你无意中将错误的类型传递给方法时,编译器可能不会发出错误,这种情况会被放大。


当前回答

在我们的办公室,我们的CTO已经明确禁止使用var关键字,原因与您所陈述的相同。

我个人认为var的使用只在new对象声明中有效,因为对象的类型在语句本身就很明显。

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

IEnumerable<TypeReturnedBySelectObject>

其他回答

摘自CodingHorror关于这一问题的文章:


不幸的是,你和其他人都错了。虽然我同意你的观点,冗余不是一件好事,但解决这个问题的更好方法应该是这样做:

MyObject m = new();

或者如果你传递参数:

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

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

最后,这并不是为了减少冗余。不要误解我,“var”在c#中对于匿名类型/投影是非常重要的,但是这里的使用是非常错误的(我已经说了很长很长一段时间了),因为你混淆了正在使用的类型。输入两次太频繁了,但是声明0次就太少了。

2008年6月20日上午08:00,c#mvp


我想如果你主要关心的是必须少打字——那么没有任何争论会动摇你使用它。

如果你只是一个查看代码的人,那么谁在乎呢?否则,在这种情况下:

var people = Managers.People

没关系,但在这种情况下:

var fc = Factory.Run();

它使我的大脑从代码的“英文”开始形成的任何即时类型推断短路。

否则,就用你最好的判断和编程“礼貌”来对待那些可能不得不为你的项目工作的人。

来自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;

显式声明range变量的类型会强制对LINQ Cast操作符进行幕后调用。此调用可能会产生意想不到的结果,并可能会损害性能。如果您在LINQ查询中遇到性能问题,像这里所示的强制转换可能是开始寻找罪魁祸首的一个地方。(此规则的一个例外是当您使用非泛型Enumerable时,在这种情况下您应该使用强制转换。)

@Keith -

在你们的比较中 IEnumerable < int > IEnumerable<double>你不需要 担心——如果你传递了错误的类型 您的代码无论如何都无法编译。

这并不完全正确——如果一个方法同时重载到IEnumerable<int>和IEnumerable<double>,那么它可能会无声地将意外推断的类型(由于程序中的其他一些更改)传递给错误的重载,从而导致不正确的行为。

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

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

在边缘情况下肯定会有分歧,但我可以告诉你我的个人指导方针。

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

变量的类型(对人来说)从上下文是很明显的 变量的确切类型(对人类来说)并不是特别相关。 [例如,你可以弄清楚算法在做什么,而不用关心你使用的是哪种容器] 类型名非常长,会影响代码的可读性(提示:通常是泛型)

相反,这些情况会促使我不使用var:

类型名称相对较短且易于阅读(提示:通常不是泛型) 从初始化式的名称来看,类型并不明显 确切的类型对于理解代码/算法非常重要 在类层次结构上,当一个人不能很容易地知道正在使用层次结构的哪个级别时

最后,我永远不会使用var的本机值类型或相应的可空<>类型(int,十进制,字符串,十进制?,……)。这里有一个隐含的假设,如果你使用var,一定有一个“原因”。

这些都是指导方针。你还应该考虑你同事的经验和技能,算法的复杂性,变量的寿命/范围,等等。

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

[编辑:删除重复的子弹]

Var还不错。记住这一点。Var还不错。重复一遍。Var还不错。记住这一点。Var还不错。重复一遍。

如果编译器足够聪明,可以从上下文中找出类型,那么您也可以。你不需要在申报时把它写下来。而智能感知让这变得更加不必要。

Var还不错。记住这一点。Var还不错。重复一遍。Var还不错。记住这一点。Var还不错。重复一遍。