在与同事讨论了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确实保持强类型,但问题是,在定义中不立即显示类型是否危险,当重载意味着当你无意中将错误的类型传递给方法时,编译器可能不会发出错误,这种情况会被放大。
在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;
有时编译器也能比开发人员“更好”地推断出需要什么——至少开发人员不了解他所使用的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 server上使用Sql),因为编译器足够聪明,可以计算出Where函数应该采用表达式>而不是Func。
示例1中的结果在返回IEnumerable时也不能在服务器上进一步查询,而在示例2中,编译器可以计算出结果是否应该是IQueryable而不是IEnumerable
你最可能需要它的时候是匿名类型(100%需要);但它也避免了琐碎案件的重复,IMO使界限更加清晰。对于简单的初始化,我不需要看到类型两次。
例如:
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);