在与同事讨论了在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项){// ...}等效更好 .
这里有关于类型安全的真正担忧 - 例如,如果我们将该查询的结果放入一个接受IEnumerable <int>和IEnumerable <double>的重载方法,则调用者可能无意中传入了错误的类型 .
var
确实保持了强类型,但问题是这个类型在定义上不是立即显而易见是危险的,当重载意味着当你无意中将错误的类型传递给方法时可能不会发出编译器错误时会被放大 .
30 回答
我仍然认为
var
可以使代码在某些情况下更具可读性 . 如果我有一个带有Orders属性的Customer类,并且我想将它分配给变量,我将这样做:我不在乎Customer.Orders是
IEnumerable<Order>
,ObservableCollection<Order>
还是BindingList<Order>
- 所有我想要的是将该列表保留在内存中以迭代它或者稍后获得它的计数 .将上述声明与以下内容对比:
对我来说,类型名称只是噪音 . 如果我回去决定改变Customer.Orders的类型(从
ObservableCollection<Order>
到IList<Order>
),那么我也需要改变这个声明 - 我首先不会使用var .我广泛使用
var
. 有人批评这会降低代码的可读性,但没有论据支持这种说法 .不可否认,这可能意味着我们正在处理的类型尚不清楚 . 所以呢?这实际上是解耦设计的重点 . 在处理接口时,您显然对变量的类型不感兴趣 .
var
更进一步,这是真的,但我认为从可读性的角度来看,论证仍然是相同的:程序员实际上不应该对变量的类型感兴趣,而应该对变量的作用感兴趣 . 这就是为什么微软也称类型推断为“鸭子打字” .那么,当我使用
var
声明变量时,变量会做什么?很容易,它可以做任何IntelliSense告诉我的事情 . 关于忽略IDE的C#的任何推理都不符合现实 . 实际上,每个C#代码都在支持IntelliSense的IDE中编程 .如果我使用的是
var
声明的变量并且混淆了变量的含义,那么我的代码就会出现根本性的错误 .var
不是原因,它只会使症状可见 . 不要责怪信使 .现在,C#团队发布了一个编码指南,指出
var
只应该用于捕获创建匿名类型的LINQ语句的结果(因为在这里,我们没有var
的真正替代品) . 好吧,搞砸了 . 只要C#团队没有纯粹的胡扯 . (对不起;我没有指向相关指南的链接 . )实际上,有一些(表面上)good explanations为什么你不应该使用
var
但我仍然认为它们在很大程度上是错误的 . 以“searchabililty”为例:作者声称var
使搜索使用MyType
的地方变得困难 . 对 . 接口也是如此 . 实际上,为什么我想知道课程的使用位置?我可能对它实例化的地方更感兴趣,这仍然是可搜索的,因为必须调用它的构造函数(即使这是间接完成的,也必须在某处提到类型名称) .您最需要的时间是匿名类型(需要100%);但它也避免了重复的微不足道的情况,IMO使线条更清晰 . 对于简单的初始化,我不需要看两次类型 .
例如:
(请不要编辑上面的hscroll - 它有点证明了这一点!!!)
VS:
但是,有时这会产生误导,并可能导致错误 . 如果原始变量和初始化类型不相同,请小心使用
var
. 例如:在我看来,Var在C#中是一个很好的东西 . 所有类型的变量仍然是强类型的,但它从定义它的赋值的右侧获得它的类型 . 因为类型信息在右侧可用,所以在大多数情况下,还必须在左侧输入它,这是不必要的并且过于冗长 . 我认为这很显着提高可读性而不降低类型安全性 .
从我的角度来看,从可读性角度来看,对变量和方法使用良好的命名约定比显式类型信息更重要 . 如果我需要类型信息,我总是可以将鼠标悬停在变量上(在VS中)并获取它 . 但是,通常,读者不需要显式类型信息 . 对于开发人员,在VS中,无论变量如何声明,您仍然可以获得Intellisense . 说完所有这些之后,可能仍然存在明确声明类型确实有意义的情况 - 也许你有一个返回
List<T>
的方法,但是你想在你的方法中把它当作IEnumerable<T>
. 要确保使用该接口,声明接口类型的变量可以使其显式化 . 或者,您可能希望声明一个没有初始值的变量 - 因为它会立即根据某些条件获取值 . 在这种情况下,您需要类型 . 如果类型信息有用或必要,请继续使用它 . 但我觉得通常没有必要,在大多数情况下,如果没有它,代码就更容易阅读 .这些都不是绝对正确的;
var
可以对可读性产生正面和负面影响 . 在我看来,当满足以下任一条件时,应使用var
:该类型是匿名的(嗯,你在这里没有任何选择,因为在这种情况下它必须是var)
根据指定的表达式显示类型(即
var foo = new TypeWithAReallyLongNameTheresNoSenseRepeating()
)var
没有性能影响,因为它被编译成IL;关于它没有任何动态 .来自C#团队的高级软件设计工程师Eric Lippert:
为什么引入了
var
关键字?强调我的 . 整篇文章,C# 3.0 is still statically typed, honest!和随后的series都很不错 .
这就是
var
的用途 . 其他用途可能不会那么好用 . 与JScript,VBScript或动态类型的任何比较都是总上铺 . 请再次注意,var
是 required ,以便在.NET中使用某些其他功能 .我认为var的使用应该与明智选择的变量名称相结合 .
我在foreach语句中使用var没有问题,前提是它不是这样的:
如果它更像这样:
...那么阅读代码的人将更有可能理解“列表”是什么 . 如果您可以控制列表变量本身的名称,那就更好了 .
这同样适用于其他情况 . 这很没用:
......但这是有道理的:
我想每个都是他自己的 . 我发现自己这样做,这只是疯了:
我需要某种12步var程序 . 我的名字是Matt,我(ab)使用var .
我们采用了“人而不是机器代码”的理念,假设您在维护模式上花费的时间比在新开发上多花费多倍 .
对我来说,这排除了编译器“知道”变量的类型的论点 - 当然,你不能在第一次编写无效代码,因为编译器会停止编译代码,但是当下一个开发人员正在阅读代码时在6个月的时间内,他们需要能够正确或错误地推断出变量的作用,并快速确定问题的原因 .
从而,
我们的编码标准是非法的,但我们的团队鼓励以下内容,因为它提高了可读性:
它不错,它更像是一种风格,往往是主观的 . 当你使用var时,它可以添加不一致性 .
另一个值得关注的案例,在下面的调用中你无法通过查看代码类型来判断由
CallMe
返回:这是我对var的主要抱怨 .
当我在方法中声明匿名委托时,我使用var,不知何故var看起来比我使用
Func
更清晰 . 考虑以下代码:EDIT :根据Julian的输入更新了最后一个代码示例
Var根本不像变种 . 该变量仍然是强类型的,只是你没有按键来获得它 . 您可以将鼠标悬停在Visual Studio中以查看其类型 . 如果您正在阅读打印的代码,那么您可能需要考虑一下才能弄清楚类型是什么 . 但是只有一行声明它并且许多行使用它,因此给出正确的名称仍然是使代码更容易理解的最佳方式 .
使用Intellisense懒惰?打字比整个名字少 . 或者有些东西工作少但不值得批评?我认为有,而var就是其中之一 .
var很难的一个特殊情况:离线代码审查,尤其是在纸上完成的代码审查 .
你不能依靠鼠标悬停 .
从我昨天写的代码来看,它当然可以简化事情:
如果没有
var
,这将非常冗长 .附录:使用具有真实类型推断的语言花费一点时间(例如F#)将显示编译器在获得正确类型的表达方面有多好 . 它当然意味着我倾向于尽可能多地使用
var
,并且使用显式类型现在表明该变量不是初始化表达式的类型 .我看不出有什么大不了的......
你仍然对'某事'有完整的智能感知,对于任何模棱两可的情况,你有单位测试,对吧? ( 你呢? )
它不是varchar,它不是暗淡的,它肯定不是动态或弱打字 . 它正在停止像这样的maddnes:
并将整个思维结构减少到:
很好,不太好:
但那就是Boo的用途 .
如果有人使用
var
关键字,因为他们不想"figure out the type",那肯定是错误的原因 .var
关键字不会创建具有动态类型的变量,编译器仍然必须知道该类型 . 由于变量始终具有特定类型,因此如果可能,类型也应在代码中明显 .例如,使用
var
关键字的充分理由是:需要的地方,即声明匿名类型的引用 .
它使代码更具可读性,即删除重复声明 .
写出数据类型通常会使代码更容易理解 . 它显示了您正在使用的数据类型,因此您不必通过首先确定代码的作用来确定数据类型 .
鉴于Intellisense现在有多强大,我不确定var是否比在类中具有成员变量或在可见屏幕区域中定义的方法中的局部变量更难读 .
如果你有一行代码如
阅读比以下更容易或更难:
我认为VAR的关键是只在适当的时候使用它,即在Linq中做事时它会促进(并且可能在其他情况下) .
如果你有一个类型的东西你应该使用它 - 不这样做是简单的懒惰(而不是通常被鼓励的创造性懒惰 - 优秀的程序员非常努力懒惰,可以考虑首先是事物的来源) .
全面禁止与首先滥用构造一样糟糕,但确实需要一个合理的编码标准 .
要记住的另一件事是,它不是一个VB类型var,它不能改变类型 - 它 is 一个强类型变量,只是推断出类型(这就是为什么有人会认为它不是不合理的在一个foreach中使用它,但出于可读性和可维护性的原因,我不同意) .
我怀疑这个会运行并运行( - :
墨菲
当然,
int
很容易,但是当变量的类型是IEnumerable<MyStupidLongNamedGenericClass<int, string>>
时,var会让事情变得更容易 .从_2571200被盗:
不幸的是,你和其他人都错了 . 虽然我同意你的看法,冗余不是一件好事,但解决这个问题的更好方法就是做类似的事情下列:
MyObject m = new();
或者如果您传递参数:
Person p = new(“FirstName”,“LastName”);
在创建新对象的位置,编译器从左侧推断出类型,而不是从右侧推断出类型 . 这比“var”还有其他优点,因为它也可以用在字段声明中(还有一些其他区域也可以用,但我不会在这里介绍它) .
最后,它并不是为了减少冗余 . 不要误解我的意思,“var”对于匿名类型/投影来说在C#中非常重要,但是这里的使用只是为了解决(我已经说了这么长时间),因为你混淆了正在使用 . 必须经常输入两次,但是将其声明为零次则太少了 .
Nicholas Paldino .NET / C#MVP于2008年6月20日08:00 AM
我想如果你主要担心的是必须输入更少 - 那么就没有任何争论会影响你使用它 .
如果您只是 ever 是那个查看您的代码的人,那么谁在乎呢?否则,在这种情况下:
没关系,但在这种情况下:
它会使我的大脑从代码的“英语”开始形成任何即时类型的推论 .
否则,只需使用您的最佳判断并对可能需要为您的项目工作的其他人进行“礼貌”编程 .
使用
var
而不是显式类型使重构变得更容易(因此我必须与先前的海报相矛盾,这些海报意味着它没有任何区别,或者它纯粹是"syntactic sugar") .您可以更改方法的返回类型,而无需更改调用此方法的每个文件 . 想像
用的像
如果您想重构
SomeMethod()
以返回IEnumerable<MySecondClass>
,则必须在使用该方法的每个位置更改变量声明(也在foreach
内) .如果你写
相反,你不必改变它 .
@aku:一个例子是代码审查 . 另一个例子是重构场景 .
基本上我不想用鼠标打猎 . 它可能不可用 .
这是一个品味问题 . 当你习惯了动态类型语言时,所有关于变量类型的烦恼都会消失 . 也就是说,如果你开始喜欢它们(我不确定是否每个人都可以,但我确实如此) .
C#的
var
非常酷,因为它看起来像动态类型,但实际上是 static 输入 - 编译器强制正确使用 .变量的类型并不那么重要(之前已经说过了) . 从上下文(它与其他变量和方法的交互)及其名称应该相对清楚 - 不要指望customerList包含
int
...我还在等着看我的老板对这个问题的看法 - 我有一个“继续”使用3.5中的任何新结构,但我们将如何处理维护?
没有,除了您不必两次写入类型名称 . http://msdn.microsoft.com/en-us/library/bb383973.aspx
在你对
IEnumerable<int>
和IEnumerable<double>
之间的比较中,无论如何都要编译 .对于类型安全没有任何顾虑,因为
var
是动态的 . 它只是编译器魔术,你所做的任何类型的不安全的调用都会被捕获 .Linq绝对需要
Var
:现在看一下intellisense中的anonEnumeration,它会出现像
IEnumerable<'a>
C#编译器非常聪明 - 如果它们的属性匹配,单独生成的anon类型将具有相同的生成类型 .
除此之外,只要你有智能感知,在上下文清晰的任何地方使用_2571224都是很有意义的 .
我想这取决于你的观点 . 由于
var
"misuse",我个人从未理解过一段代码,而且我的同事和我一直在使用它 . (我同意Intellisense在这方面是一个巨大的帮助 . )我欢迎它作为一种消除重复性的方法 .毕竟,如果声明如此
实际上是不可能处理的,没有人会使用动态类型语言 .
只有在清楚地看到使用什么类型时我才使用var .
例如,在这种情况下我会使用var,因为您可以立即看到x将是“MyClass”类型:
我不会在这种情况下使用var,因为你必须将鼠标拖过代码并查看工具提示以查看MyFunction返回的类型:
特别是,在右侧不均匀的情况下,我使用var方法,但只有一个值:
(因为编译器无法知道我是否需要byte,short,int或者其他)
对我来说,对
var
的反感说明了为什么.NET中的双语是重要的 . 对于那些也完成VB .NET的C#程序员来说,var
的优势直观明显 . 标准C#声明:在VB .NET中,输入以下内容是等效的:
但是,在VB .NET中没有人这样做 . 这将是愚蠢的,因为自.NET的第一个版本以来你已经能够做到这一点......
...创建变量并在一个相当紧凑的行中初始化它 . 啊,但如果你想要
IList<string>
,而不是List<string>
怎么办?好吧,在VB .NET中,这意味着你必须这样做:就像你'd have to do in C#, and obviously couldn' t使用
var
:如果你需要类型不同的东西,它可以 . 但良好编程的基本原则之一是减少冗余,而这正是var所做的 .
将它用于匿名类型 - 那里有's what it' . 其他任何东西都用得太过分了 . 像许多在C长大的人一样,除非必须,否则我会看右边 . 使用
var
进行任何旧的声明都会让我一直这样做,我个人觉得这很不舒服 .那些说法很重要,用你所看不到的全部图片 . 每个人都会接受其他人的错误,不得不处理完全不同的命名惯例,或者 - 经典的抱怨 - 支撑样式,而不是添加整个'
var
或不使用' thing into the mix. The worst case will be where one programmer didn'然后沿着一个喜欢它的维护者,并使用它扩展代码 . 所以现在你有一个邪恶的混乱 .标准是一件好事,正是因为它们意味着你所处的风格造成了差异 .
我不介意动态打字,我不介意打印输入 - 用于为他们设计的语言 . 我非常喜欢Python . 但是C#被设计为一种静态明确类型的语言,它应该如何保留 . 打破匿名类型的规则已经够糟糕了;让人们更进一步,进一步打破语言的习语,这是我不满意的事情 . 既然精灵已经不在瓶子里了,它就永远不会再回来了.C#将会变成阵营 . 不好 .
很多时候在测试过程中,我发现自己有这样的代码:
现在,有时,我想看看SomeOtherThing本身包含的内容,SomeOtherThing与CallMethod()返回的类型不同 . 因为我使用var,我只是改变了这个:
对此:
如果没有var,我还必须继续改变左侧的声明类型 . 我知道它很小,但非常方便 .
对于认为
var
节省时间的afficionados,键入的键击次数更少:比
如果你不相信我,请算上他们......
19对21
我会解释是否必须,但只是尝试一下......(取决于你的智能感知的当前状态,你可能需要为每一个输入更多)
对于你能想到的每种类型都是如此!
我的个人感觉是永远不应该使用var,除非类型未知,因为它会降低代码中的识别可读性 . 识别类型比整行更需要大脑 . 了解机器代码和位的老定时器确切地知道我在说什么 . 大脑并行处理,当你使用var时,你强制它序列化它的输入 . 为什么有人想让他们的大脑更努力?这就是计算机的用途 .
我将var分布在所有地方,对我来说唯一可疑的地方是内部短型,例如我更喜欢
int i = 3;
而不是var i = 3;