55

这是我在编程时总是想知道的一个问题:我们在编写代码时要使用什么:

var myFiles = Directory.GetFiles(fullPath);

或者

string[] myFiles = Directory.GetFiles(fullPath);

var是新的,是一个隐式类型的局部变量,所以我们只能在本地使用,它有不能为空等规则,但我想知道我们是否能“正常”使用它。

“通常”部分说,不是在Anonymous TypesObject 和 Collection InitializersQuery Expressions中使用 var 匿名对象的意图,所以我的意思是......就像上面的例子一样。

你怎么认为?

4

8 回答 8

62

除了明显使用varLINQ 之外,我还使用它来缩写毛茸茸的变量声明以提高可读性,例如:

var d = new Dictionary<string, Dictionary<string, Queue<SomeClass>>>();

总的来说,我从静态类型中获得了一种安慰(因为需要一个更好的词),这让我不愿意放弃它。我喜欢在声明变量时知道自己在做什么的感觉。声明一个变量不仅仅是告诉编译器一些事情,它是告诉阅读你的代码的人一些事情。

让我给你举个例子。假设我有一个返回List<string>. 这段代码当然是正确的,我认为 90% 的 C# 开发人员可能会这样写:

List<string> list = MyMethod();

很明显,对吧?事实上,这是一个您可以轻松使用的地方var

真是的。但是这个版本的代码不仅仅是声明一个变量,它告诉我编写它的人打算做什么:

IEnumerable<string> list = MyMethod();

编写该代码的开发人员告诉我“我不会更改此列表,也不会使用索引来访问其成员。我要做的就是遍历它。” 在一行代码中可以获取大量信息。如果您使用var.

当然,如果你一开始没有使用它,你就不会放弃它。如果你是那种会编写那行代码的开发人员,你已经知道你不会var在那里使用。

编辑:

我刚刚重读了 Jon Skeet 的帖子,Eric Lippert 的这句话让我大吃一惊:

隐式键入的本地人只是一种小方法,您可以通过这种方式不强调如何,从而强调什么。

我认为实际上在很多情况下使用隐式类型会留下隐含的内容。不纠结于什么也没关系。例如,我会随便写一个 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>,并且我可以在此处看到正在选择的对象的类型。

这是一个没有明确说明的情况。留给我去推断。

现在,在我使用 LINQ 的大约 90% 的情况下,这一点都不重要。因为 90% 的时间,下一行代码是:

foreach (DataRow r in rows)

但是不难想象在其中声明rows为非常有用的IEnumerable<DataRow>代码 - 查询许多不同类型的对象的代码,将查询声明放在迭代旁边是不可行的,它会是能够rows使用 IntelliSense 进行检查很有用。那是什么,而不是如何。

于 2008-10-25T20:58:35.107 回答
43

你会在这个问题上得到各种各样的意见——从“到处使用 var”到“只使用匿名类型的 var,你基本上必须这样做”。我喜欢Eric Lippert 的看法

所有的代码都是抽象的。代码“真正”在做什么是在操纵数据?不,数字?位?不,电压?不,电子?是的,但是在电子级别理解代码是个坏主意!编码的艺术是弄清楚对观众来说正确的抽象级别是什么。

在高级语言中,代码做什么(语义上)和代码如何完成它之间总是存在这种张力。如果要成功进行更改,维护程序员需要了解内容和方式。

LINQ 的全部意义在于它大大地淡化了“如何”并大量强调了“什么”。通过使用查询理解,程序员对未来的听众说“我相信你不应该知道也不应该关心这个结果集是如何计算的,但你应该非常关心结果集的语义是什么。” 它们使代码更接近正在实现的业务流程,而远离实现它的比特和电子。

隐式键入的本地人只是一种小方法,您可以通过这种方式不强调如何,从而强调什么。在特定情况下这是否是正确的做法是一个判断电话。所以我告诉人们,如果类型的知识是相关的,并且它的选择对于方法的持续运行至关重要,那么不要使用隐式类型。显式输入说“我告诉你这是有原因的,请注意”。隐式类型表示“这个东西是 List 还是 Customer[] 并不重要,重要的是它是一个客户的集合。”

如果类型不是相当明显,我个人不倾向于使用它 - 我将 LINQ 查询包括为“相当明显”。例如,我不会这样做,因为返回 a而不是(比如说) a (或完全是其他东西)Directory.GetFiles并不是很明显- 这对你以后做的事情有很大的影响。string[]FileInfo[]

如果在赋值运算符的右侧有一个构造函数调用,我更有可能使用var: 很明显类型是什么。这对于复杂的泛型类型特别方便,例如Dictionary<string,List<int>>.

于 2008-10-25T19:25:47.727 回答
12

就我个人而言,我只在两个地方使用 var:

  1. 使用匿名类型,即。LINQ 相关(在某些情况下需要 var)
  2. 当语句声明并构造相同类型的特定类型时

IE。这是第 2 点的示例:

var names = new List<String>();

编辑:这是为了回应 Jon Skeet 的问题。

上面的答案实际上被简化了。基本上,我使用var类型为:

  1. 没必要知道(虽然不是很多地方)
  2. 不可能知道(LINQ,匿名类型)
  3. 否则已知,或从代码中清除

在工厂方法的情况下,您在编写代码的地方只需要知道您返回的对象是某种类型的后代,并且某种类型具有静态工厂方法,那么我会使用变量。像这样:

var connection = DatabaseConnection.CreateFromConnectionString("...");

上面的例子是我的代码中的一个真实例子。很明显,至少对我和使用此代码的人来说,该连接是 DatabaseConnection 的后代,但既不需要理解代码也不需要使用它的确切类型。

于 2008-10-25T19:30:53.723 回答
9

我尝试了“到处使用 var”的风格……这就是我没有继续使用它的原因。

  1. 有时会降低可读性
  2. 在 = 之后限制 Intellisense
  3. 键入“var”实际上并不比键入“int”、“string”等短很多,尤其是使用智能感知。

话虽如此,我仍然将它与 LINQ 一起使用。

于 2008-10-25T19:41:45.213 回答
4

来自函数式编程领域,类型推断占主导地位,我var尽可能为所有本地人使用。

在 Visual Studio 中,如果您想知道任何 local 的类型是什么,您所要做的就是将鼠标悬停在它上面。

于 2008-10-26T04:21:12.873 回答
3

这篇文章对何时使用 var 类型接口或对象类型有一些很好的指导。

于 2008-10-25T20:15:41.837 回答
3

我倾向于在var任何地方使用,但我的同事说停止,它对我们来说不太可读。所以我现在var只使用匿名类型、LINQ 查询以及右侧的构造函数在哪里。

于 2008-12-13T16:41:04.790 回答
1

我认为注意到 Haskell 通常如何处理这很有趣。由于Curry-Howard 同构,可以推断 Haskell 中任何表达式的(最一般的)类型,因此基本上不需要类型声明,除了少数例外;例如,有时您有意将类型限制为比推断出的更具体的内容。

当然,需要什么和推荐什么不是一回事;在实践中,约定似乎是顶级定义始终具有类型声明,而本地化定义则省略了类型声明。这似乎在整个定义的明确性和可读性之间取得了很好的平衡,与本地“帮助”或“临时”定义的简洁性形成对比。如果我理解正确,首先你不能使用var“顶级”定义(如方法或全局函数),所以我猜这var在 C# 世界中转化为“在任何地方都可以使用”。当然,键入“ int”与“ ”的击键次数相同var,但大多数示例会比这更长。

于 2008-10-25T21:46:39.893 回答