在与同事讨论了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确实保持强类型,但问题是,在定义中不立即显示类型是否危险,当重载意味着当你无意中将错误的类型传递给方法时,编译器可能不会发出错误,这种情况会被放大。


当前回答

如果你知道类型,就使用类型。 如果你不知道哪种类型,为什么不呢? 如果您不知道类型,也没关系——您已经找到了唯一有效的用法。

我很抱歉,但如果你能做到的最好的是“它使代码全部对齐”,那不是一个好答案。找一种不同的方式来格式化代码。

其他回答

我不明白这有什么大不了的。

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

你仍然对“某事”有完全的智能感知,对于任何不明确的情况,你都有单元测试,对吗?(是吗?)

它不是varchar,也不是dim,当然也不是动态或弱类型。它像这样阻止疯狂的人:

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

把这些杂乱的思想归纳为:

var v = new List<somethinglongtypename>();

不错,但不如:

v = List<somethinglongtypename>();

但这就是布的作用。

在我看来,大量使用var是没有问题的。它本身不是一个类型(您仍然在使用静态类型)。相反,这只是一个节省时间的方法,让编译器自己判断要做什么。

像任何其他节省时间的方法(例如自动属性)一样,在到处使用它之前,最好先了解它是什么以及它是如何工作的。

Apart from readability concerns, there is one real issue with the use of 'var'. When used to define variables that are assigned to later in the code it can lead to broken code if the type of the expression used to initialize the variable changes to a narrower type. Normally it would be safe to refactor a method to return a narrower type than it did before: e.g. to replace a return type of 'Object' with some class 'Foo'. But if there is a variable whose type is inferred based on the method, then changing the return type will mean that this variable can longer be assigned a non-Foo object:

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

所以在这个例子中,改变getFoo的返回类型会使getNonFoo的赋值变为非法。

如果getFoo和它的所有用途都在同一个项目中,这不是什么大问题,但如果getFoo在一个库中供外部项目使用,如果他们像这样使用'var',你就不能确保缩小返回类型不会破坏某些用户的代码。

正是由于这个原因,当我们在Curl编程语言中添加类似的类型推断特性(在Curl中称为'def')时,我们阻止了对使用这种语法定义的变量的赋值。

我仍然认为var在某些情况下可以使代码更具可读性。如果我有一个带有Orders属性的Customer类,我想把它赋值给一个变量,我只需要这样做:

var orders = cust.Orders;

我不在乎顾客。Orders是IEnumerable<Order>, ObservableCollection<Order>或BindingList<Order> -我想要的只是将该列表保存在内存中,以便稍后对其进行迭代或获取其计数或其他内容。

将上述声明与:

ObservableCollection<Order> orders = cust.Orders;

对我来说,类型名只是噪音。如果我回头决定改变客户的类型。沿着轨道的订单(从ObservableCollection<Order>到IList<Order>),然后我也需要改变声明-如果我在第一个地方使用var,我就不必这样做。

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

如果您指定了特定的类型,则可能会有编译器无声地将运行时强制转换插入程序的风险!

foreach (Derived d in listOfBase)
{

上面的代码将被编译。但是编译器会插入一个从Base到Derived的向下转换。因此,如果列表中的任何内容在运行时不是派生的,则存在无效的强制转换异常。类型安全受到损害。隐形演员太可怕了。

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