使用什么:var或对象名称types?
这是一个问题,编程时,我总是想知道:当我们写代码时要用什么:
var myFiles = Directory.GetFiles(fullPath);
要么
string[] myFiles = Directory.GetFiles(fullPath);
var是新的,是一个隐式types局部variables ,所以我们只能在本地使用,它的规则不能为空等,但我不知道我们是否有任何使用“正常”的优势。
“正常”的部分说,不是在匿名types , 对象和集合初始值设定项和查询expression式那里是有意使用var匿名对象,所以我的意思是…就像上面的例子。
你怎么看?
除了var
与LINQ的显而易见的用法外,我还使用它来缩写多变的声明以提高可读性,例如:
var d = new Dictionary<string, Dictionary<string, Queue<SomeClass>>>();
总的来说,我从静态input中得到了一种安慰(因为想要更好的词),这让我不愿意放弃。 我喜欢这样的感觉,即当我声明一个variables时,我知道自己在做什么。 声明variables不仅仅是告诉编译器一些东西,而是告诉读取代码的人。
让我举一个例子。 假设我有一个返回List<string>
。 这段代码当然是正确的,我想这是90%的C#开发人员可能写的:
List<string> list = MyMethod();
很明显,对吗? 事实上,这里有一个你可以轻松使用var
。
真的够了。 但是这个版本的代码不仅仅是声明一个variables,而是告诉我编写它的人打算做什么:
IEnumerable<string> list = MyMethod();
编写代码的开发人员告诉我:“我不会改变这个列表,也不会使用索引来访问它的成员,我要做的就是迭代它。 这是在一行代码中得到的很多信息。 这是你放弃,如果你使用var
。
当然,如果你不是首先使用它,你是不会放弃的。 如果你是那种编写这行代码的开发者,你已经知道你不会在那里使用var
。
编辑:
我只是重读了Jon Skeet的post,Eric Lippert的这句话引起了我的兴趣:
隐式types化的本地人只是一个小的方法,你可以不去强调如何从而强调什么。
我认为,实际上在很多情况下使用隐式打字就是留下什么隐含的。 这是没关系的。 例如,我会随便写一个LINQ查询,如:
var rows = from DataRow r in parentRow.GetChildRows(myRelation) where r.Field<bool>("Flag") orderby r.Field<int>("SortKey") select r;
当我阅读代码时,我在阅读时想到的一件事是“ rows
是IEnumerable<DataRow>
。 因为我知道LINQ查询返回的是IEnumerable<T>
,我可以看到在那里select的对象的types。
这是一个没有明确表示的情况。 这是我留下来推断。
现在,在我使用LINQ的情况下,大约90%的情况并不重要。 由于90%的时间,下一行代码是:
foreach (DataRow r in rows)
但是,设想将rows
声明为IEnumerable<DataRow>
非常有用的代码是很有用的 – 代码中查询了很多不同types的对象,将查询声明放在迭代旁边是不可行的,并且能够使用IntelliSense检查rows
是有用的。 这是一个什么东西,而不是一个事情。
你会在这个问题上得到各种各样的意见 – 从“无处不在”到“只使用匿名types的var,你基本上必须这样做”。 我喜欢Eric Lippert对此的看法 :
所有代码都是抽象的。 代码是“真正”在做什么操纵数据? 号码? 位? 号电压? 电子号? 是的,但是在电子层面理解代码是一个坏主意! 编码的艺术就是搞清楚什么是适当的抽象层次。
在高级语言中,代码所做的事情(语义上)和代码如何实现它之间总是存在这种紧张关系。 维护程序员需要了解什么以及如何才能成功进行更改。
LINQ的重点在于大力强调“如何”,大力强调“什么”。 通过使用查询理解,程序员正在对将来的观众说:“我相信你不应该知道也不关心这个结果集是如何计算的,但是你应该非常关心结果集的语义。” 他们使代码更接近正在实施的业务stream程,远离实现业务的位和电子。
隐式types化的本地人只是一个小的方法,你可以不去强调如何从而强调什么。 在特定情况下做这件事是否正确是一个判断。 所以我告诉人们,如果这种types的知识是相关的,而且它的select对方法的持续运作是至关重要的,那么就不要使用隐式types。 明确的打字说:“我告诉你这是如何工作的原因,注意”。 隐式打字说“这个东西是一个List还是一个Customer []无关紧要,重要的是它是一个客户的集合。
我个人不倾向于使用它,如果types不是很明显 – 我把LINQ查询包括在“合理的明显”中。 我不会为Directory.GetFiles
这样做,因为它不是真的很明显,返回一个string[]
而不是(比如说)一个FileInfo[]
(或其他完全) – 这对你来说是一个很大的改变稍后再做。
如果在赋值运算符的右边有一个构造函数调用,那么我更有可能使用var
:显然这个types是什么。 这对于复杂的genericstypes尤其方便,例如Dictionary<string,List<int>>
。
我个人只在两个地方使用var:
- 用匿名types,即。 相关的LINQ(在某些情况下需要var)
- 当声明声明并构造相同types的特定types时
即。 这是第2点的一个例子:
var names = new List<String>();
编辑 :这是针对Jon Skeet的问题。
上面的答案实际上是简化的。 基本上,我使用var的types是:
- 不必知道(虽然没有那么多地方)
- 不可能知道(LINQ,匿名types)
- 否则已知,或从代码中清除
在工厂方法的情况下,在你写代码的地方你需要知道的是你得到的对象是某种types的后代,而某种types有一个静态工厂方法,那么我会使用变种 喜欢这个:
var connection = DatabaseConnection.CreateFromConnectionString("...");
上面的例子是我的代码的一个真实的例子。 很明显,至less对我和使用这个代码的人来说,这个连接是一个DatabaseConnection后裔,但是不需要明确的types来理解代码,也不需要使用它。
我尝试了“使用无处不在”的风格…这就是为什么我没有继续使用它。
- 有时降低可读性
- 在=后限制智能感知
- 键入“var”实际上并不比input“int”,“string”等短得多,特别是对于intellisense。
这样说,我仍然使用LINQ。
来自函数式编程的地方,types推理规则当天,我尽可能使用var
为所有当地人。
在Visual Studio中,如果您想知道任何本地types是什么,您只需将鼠标hover在其上即可。
这篇文章对于何时使用vartypes的接口或对象types有一些很好的指导。
我倾向于在所有地方使用var
,但是我的同事说停下来,这对我们来说是不太可读的。 所以我现在只使用var
匿名types,LINQ查询和右边的构造函数。
我认为有趣的是要注意如何通常在Haskell中处理这个问题。 由于Curry-Howard同构 ,Haskell中任何expression式的(最一般的)types都可以被推断出来,因此types声明本质上不是必需的,除了less数例外。 例如,有时候你会故意想把这个types限制在比推断更具体的东西上。
当然,所要求的和推荐的是不一样的。 在实践中,惯例似乎是顶级定义总是有types声明,而本地化定义则省略了types声明。 这似乎在整体定义的明确性与可读性之间取得了很好的平衡,而与当地“帮手”或“临时”定义的简洁性 – 可读性形成鲜明对照。 如果我理解正确,首先不能将var
用于“顶级”定义(比如方法或全局函数),所以我想这意味着在C#世界中将“ var
all all”变成可用的。 当然,键入“ int
”与“ var
”键击次数相同,但是大多数例子会比这个长。