在与同事讨论了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时,我看看这些标准:
变量的类型(对人来说)从上下文是很明显的
变量的确切类型(对人类来说)并不是特别相关。
[例如,你可以弄清楚算法在做什么,而不用关心你使用的是哪种容器]
类型名非常长,会影响代码的可读性(提示:通常是泛型)
相反,这些情况会促使我不使用var:
类型名称相对较短且易于阅读(提示:通常不是泛型)
从初始化式的名称来看,类型并不明显
确切的类型对于理解代码/算法非常重要
在类层次结构上,当一个人不能很容易地知道正在使用层次结构的哪个级别时
最后,我永远不会使用var的本机值类型或相应的可空<>类型(int,十进制,字符串,十进制?,……)。这里有一个隐含的假设,如果你使用var,一定有一个“原因”。
这些都是指导方针。你还应该考虑你同事的经验和技能,算法的复杂性,变量的寿命/范围,等等。
大多数时候,没有完美的正确答案。或者,这并不重要。
[编辑:删除重复的子弹]
在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
};
现在看看智能感知中的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#编译器非常聪明——单独生成的anon类型如果它们的属性匹配,将具有相同的生成类型。
除此之外,只要你有智能感知,在上下文清楚的地方使用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;