[译文] 为什么你在 C# 里总是应该使用 "var" 关键字

[译文] Why You Should Always Use the ‘var’ Keyword in C# (为什么你总是应该在 C# 里使用 "var" 关键字)

Using the ‘var’ keyword in C# has always spurred a hot debate among developers. I believe ‘var’ should be used at all times. I believe this not because I choose to be “lazy,” as those who argue against it frequently claim. Of all the reasons I use ‘var’, laziness is not one of them.

在 C# 中使用 var 关键字一直引起开发人员的激烈争论, 我认为应始终使用 var. 我相信这不是因为我选择变得 懒惰, 正如经常声称反对它的人的那样, 在我使用 var 的所有原因中, 懒惰不是其中之一.

I’ve argued for the constant use of ‘var’ countless times; this blog post is a collection of thoughts that I have compiled resulting from my arguments. Below are my reasons for using ‘var’ all of the time.

我主张无时无刻地使用 var, 这篇博客文章是我根据自己的论点整理出的想法的集合, 以下是我一直使用 var 的原因.

原文

It decreases code-coupling (减少代码耦合)

Coupling between code and its dependent code can be reduced by using ‘var’. I do not mean coupling from an architectural perspective nor at an IL-level (the type is inferred anyway), but simply at the code level.

使用 var 可以减少代码与其从属代码之间的耦合, 我的意思是, 不是从体系结构的角度耦合, 也不是在IL级别(无论如何推断类型), 而是在代码级别.

Example (示例)

Imagine there are 20 explicit type references spanning over twenty code files to an object that returned an another object of type IFoo. By explicit type references, I mean by prefacing each variable name with IFoo. What happens if IFoo changes to IBar, but the interface’s methods are kept the same?

假设有 20 个显式类型引用, 跨越 20 多个代码文件, 返回一个类型为 IFoo 的对象. 通过显式类型引用, 我的意思是在每个变量名前面加上 IFoo, 如果将 IFoo 更改为 IBar, 接口的方法保持不变, 会发生什么?

Wouldn’t you have to change it in 20 distinct places? Doesn’t this increase coupling? If ‘var’ was used, would you have to change anything? Now, one could argue that it is trivial to change IFoo to IBar in a tool like ReSharper and have all of the references changed automatically. However, what if IFoo is outside of our control? It could live outside the solution or it could be a third-party library.

是否需要在 20 个不同的地方就行修改? 这不就是增加了耦合? 若使用 var, 需要修改什么吗? 现在, 有人可能会争辩道, 在 ReSharper 之类的工具中将 IFoo 修改为 IBar 并不重要, 且可以自动更正所有引用. 但是, 倘若 IFoo 超出我们的控制范围了? 它可以存在与解决方案之外, 也可以是第三方库.

It is completely redundant with any expression involving the "new" operator (它对于任何涉及 "new" 运算符的表达式都是完全多余的)

Especially with generics:

尤其是在泛型:

ICalculator<GBPCurrency, GBPTaxType> calculator = new GBPCalculator<GBPCurrency, GBPTaxType>();

can be shorted to:

可以缩写为:

var calculator = new GBPCalculator<GBPCurrency, GBPTaxType>();

Even if calculator is returned from a method (such as when implementing the repository pattern), if the method name is expressive enough it is obvious the object is a calculator. The name of the variable should be expressive enough for you to know what the object it represents is. This is important to realize: the variable expresses not what type it represents, but what the instance of that type actually is. An instance of a type is truly an object, and should be treated as such.

即使计算器是从方法返回的 (例如, 在实现仓储模式时), 如果方法名具有足够的表达力, 则对象显然是个计算器. 变量的名称应该具有足够的表达力, 让人知道它所表达的对象是什么. 认识到这点十分重要: 变量表示的不是它所表示的类型, 而是该类型的实例实际上是什么. 一个类型的实例确实是一个对象, 应该这样对待.

There is a distinction between an object and its type: an object exists at runtime, it has properties and behaviors; types simply describe what an object should be. Knowing what type an object should be simply adds more noise to the source code, distracting the coder from what an object really is.

对象和它的类型之间有个区别: 对象的属性和行为存在于运行时, 类型只是简单地表述了对象应该是什么, 知道对象应该是什么类型, 只会给源代码带来更多的干扰, 从而是开发者分心, 无法真正了解对象是什么.

An object may be brought into this world by following the rules governed by a type, but this is only secondary information. What the object actually is and how it behaves is more important than its type. When we use an object at runtime, we are dependent on its methods and properties, not its type. These methods and properties are an object’s behaviors, and it is behaviors we are dependent upon.

对象可以通过遵循由类型控制的规则而引入, 但这仅仅是辅助信息, 对象实际是什么以及其行为比其类型更重要. 当我们在运行时使用一个对象时, 依赖于它的方法和属性, 而不是它的类型. 这些方法和属性是对象的行为, 也是我们所依赖的行为.

The argument for knowing a variable‘s type has been brought up in the past. The move from Hungarian notation in Microsoft-based C++ to non-Hungarian notation found in C# is a great example of this once hot topic. Most Microsoft-based C++ developers at the time felt putting type identifiers in front of variable names was helpful, yet Microsoft published coding standards for C# that conflicted with these feelings.

过去曾提出了解变量类型的争议, 从基于微软的 C++ 中的匈牙利命名法到 C# 中的非匈牙利命名法的转变, 就是这个曾经热门话题的一个很好的例子. 当时, 大多数基于微软的 C++ 开发者都认为将类型标识符放在变量之前是有帮助的, 然而, 这与微软发布的 C# 编码标准与之相冲突.

It was a major culture change and mind-shift to get developers to accept non-Hungarian notation. I was among those who thought that non-Hungarian variable naming was downright wicked heresy and anyone following such a practice must be lazy and did not care about their profession. If knowing a variable’s type is so important, shouldn’t we then preface variable names in Hungarian style to know more information about an object‘s type?

让开发者接受非匈牙利命名法是个重大的文化变革和思想转变. 我曾经就认为, 任何遵循非匈牙利变量命名法的人一定是懒惰的, 不管他是什么职业, 是彻头彻尾邪恶的异端邪教. 如果知道变量的类型是非常重要的, 那么我们难道不应该以匈牙利命名法的风格前缀变量名以了解有关对象的类型的更多信息吗?

You shouldn‘t have to care what the type of an object is (不必关心对象的类型)

You should only care what you are trying do with an object, not what type an object may come from. The methods you are attempting to call on an object are its object contract, not the type. If variable names, methods, and properties are named appropriately, then the type is simply redundant.

应该专注于利用对象做什么, 而非关注对象来自何种类型. 尝试调用对象的方法是对象契约, 而非类型. 若对变量名, 方法和属性作了恰当的命名, 那么类型则是冗余.

In the previous example, the word "calculator" was repeated three times. In that example, you only need to know that the instance of a type (the object) is a calculator, and it allows you to call a particular method or property.

如前例所示, 单词 calculator 重复了三次, 示例中, 只需要知道类型 (对象) 的实例是一个 calculator (计算器), 并且它允许调用特定的方法或者属性.

The only reason a calculator object was created was so that other code could interact with its object contract. Other code needs the calculator’s methods and properties to get something done. This need has no dependency on any type, only on an object’s behaviors..

创建 calculator (计算器)对象的惟一原因是, 其他代码可以与其对象契约进行交互. 其他代码需要计算器的方法和属性来完成一些工作. 这种需求不依赖于任何类型, 只依赖于对象的行为.

For example, as long as the object is a calculator, and the dependent code needs to call a method named ,” then the dependent code is coupled to an object with a method called “CalculateTax” and not a specific type. This allows for much more flexibility, because now the variable can reference any type as long as that type supports the “CalculateTax” method.

比如, 依赖代码需要调用一个名为 "CalculateTax" 的方法, 对象只要是个 calculator (计算器), 那么依赖代码就会与一个名为 CalculateTax 的方法 (而不是特定类型) 耦合到一个对象上, 这允许更大的灵活性, 因为现在变量可以引用任何类型, 只要该类型支持 CalculateTax 方法.

‘var’ is less noisy than explicitly referencing the type (与显式引用类型相比, “var”的噪声更小)

As programming languages evolve, we spend less time telling the compiler and the computer what to do and more time expressing problems that exist in the specific domain we are working in.

随着编程语言的发展, 我们花更少的时间告诉编译器和计算机该做什么, 而是花更多的时间来表达我们工作的存在于特定领域的问题.

For example, there are a number of things in C++ that are very technical with respect to the machine, but have nothing to do with the domain. If you are a customer of Quicken or Microsoft Money, all you really want to do is manage your finances better. These software packages allow you to do that.

比如, 在 C++ 中, 有许多与计算机相关的技术问题, 却与特定领域无关. 如果你是 Quicken (一款家庭及个人财务管理软件) 或 Microsoft Money 的用户, 你真正想做的只是更好地管理你的财务. 这些软件也正是让你这样做的.

The better a software package can do this for you, the more valuable it is to you. Therefore, from a development perspective value is defined by how well a software package solves a user‘s problem. When we set out to develop such software, the only code that is valuable is the code that contributes to solving a particular user’s problem. The rest of the code is unfortunately a necessary waste, but is required due to limitations of technology.

一个软件为你做得越好, 它对你就越有价值. 因此, 从开发的角度来看, 价值是由软件解决用户问题的能力来定义的. 当我们开始开发这样的软件时, 唯一有价值的代码是帮助解决特定用户问题的代码. 遗憾的是, 剩下的代码是必要的浪费, 这是由于技术限制而必需的.

If we had infinite memory, we would not need to worry about deleting pointers in C++ or garbage collection in C#. However, memory is a limitation and therefore the technician in us has to find ways of coping with this limitation.

如果我们的内存是无限的, 就不必担心删除 C++ 中的指针或 C# 中的垃圾回收. 然而, 内存是有限的, 因此我们的技术人员必须寻找对付这种限制的办法.

The inclusion of ‘var’ into the C# language was done for a reason and bookmarks another iteration of C# (particularly C# 3.0). It allows us to spend less time telling the compiler what to do and more time thinking about the problem we are trying to solve.

将 "var" 包含在 C# 语言中是有原因的, 标志着 C# 的一次革新 (尤其是 C# 3.0). 它让我们可以花更少的时间告诉编译器应该做什么, 花更多的时间思考我们需要解决的问题.

Often I hear dogma like "use var only when using anonymous types." Why then should you use an anonymous type? Under these conditions you usually do not have a choice, such as when assigning variables to the results of LINQ expressions. Why do you not have a choice when using LINQ expressions? It‘s because the expression is accomplishing something more functional and typing concerns are the least of your worries.

经常听到这样的教条: "只能在使用匿名类型时才能 var." 那么为什么要使用匿名类型呢? 在这些情况下, 通常没有选择的余地, 比如在将变量分配给 LINQ 表达式的结果时. 为什么在使用 LINQ 表达式时没得选? 这正是因为表达式实现了一些更为实用的功能, 且类型问题是最不需要担心的.

In the ideal C# world, we would not have to put any words in front of a variable name at all. In fact, prefacing a variable with anything just confuses the developer even further, and allows for poor variable names to become a standard whereby everyone is reliant upon explicit type references.

在理想的 C# 编程环境中, 我们压根就不需要在变量名前缀任何单词. 实际上, 在变量前缀任何东西只会使开发者更加困惑, 并让糟糕变量名成为每个开发者都在显式依赖引用的标准.

Arguments against using ‘var’ (反对使用“var”的论据)

Some of the arguments I have heard against using ‘var’ and my responses to these are:

我看到一些反对使用 var 的论点, 对此我的回答是:

  • “It reduces clarity” – How? By removing the noise in front of a variable name, your brain has only one thing to focus on: the variable name. It increases clarity.

"它降低清晰度" - 为什么? 通过消除变量前面的噪音, 大脑只需要关注唯一的一件事: 变量名. 它增加了清晰度.

  • “It reduces readability and adds ambiguity” – This is similar to #1: readability can be increased by removing words in front of the variable and by choosing appropriate variable names and method names. Focusing on type distracts you from the real business problem you are trying to solve.

"它降低了可读性, 同时增加了模糊性" - 这与第一条相似: 可读性可以通过删除变量前面的单词, 以及选择适当的变量名和方法名来提高. 专注于类型会分散对要解决的实际业务问题的注意力.

  • “It litters the codebase” – This is usually an argument for consistency. If your codebase uses explicit type references everywhere, then by all means do not use ‘var’. Consistency is far more important. Either change all explicit references in the codebase to ‘var’ or do not use ‘var’ at all. This is a more general argument that applies to many more issues, such as naming conventions, physical organization policies, etc.

"它让代码库变得乱糟糟" - 这大概是一致性的理由. 如果现存的代码库已经使用显示类型引用, 那么别使用 var, 一致性更重要. 要么将代码库中所有显示引用修改为 var, 要么从不使用 var. 这是个更普遍的观点, 适用于很多情形, 比如命名约定, 物理文件组织策略等等.

As a final thought, why do we preface interface names with “I” but not class names with “C” as we did in the days when Microsoft-C++ was the popular kid in school?

最后思考下, 当在 Microsoft C++ 在学校大受欢迎时, 为什么我们要在接口名前缀 "I" 而不在类名前缀 "C"?

原文地址:https://www.cnblogs.com/xixixiao/p/why-you-should-always-use-var-keyword.html

时间: 2024-10-19 19:23:57

[译文] 为什么你在 C# 里总是应该使用 "var" 关键字的相关文章

尝试在C++里实现 Java 的 synchronized 关键字

话说Java里有个很强大的关键字叫synchronized,可以方便的实现线程同步.今天异想天开,尝试在C++里模拟一个类似的. 最近在学习C++的STL,看见智能指针这章节时,无不感叹利用语言的丰富特征,来各种实现各种巧妙的构思.最经典的莫过于使用栈对象构造/析构函数,来维护局部资源的初始化和释放.照着这个巧妙的方法,依样画葫芦自己也来写一个,来实现局部代码线程同步. Java里的synchronized有两种形式,一种是基于函数的,另种则是语块的.前者受C++的语法所限,估计是没法实现了,所

函数里面的global 和 nonlocal 关键字的使用

"""global和nonlocal关键字:当修改全局变量时,使用global关键字声明:当修改嵌套作用域(enclosing作用域,外层非全局作用域)时,使用nonlocal关键字声明: """ #修改全局变量时,使用global关键字声明: a=10def f():        global a  # global修改全局变量,先声明    a=20    print(a)        def f1():        a=30     

JS里的let与var(与君共勉)

setTimeout延时器,平时用到的都是setInterval,并没有对setTimeout过多的了解过,今天遇到一个问题 第二个不用多说,输出五个5 第二个,分别在谷歌和火狐上运行了一遍,火狐是0,1,2,3,4,输出,谷歌0.1.2.3.4随机输出,这是浏览器处理问题,alert会阻止程序继续向下运行,再此小编不过多解释. let形成了独立的块级作用域,彼此不受影响,let中全文中的i不是一个而var中全文中的i是同一个i.就导致了输出结果不同.

LINQ(LINQ to DataSet)

http://www.cnblogs.com/SkySoot/archive/2012/08/21/2649471.html DataTable.Select()方法使用和 SQL 相似的过滤语法从 DataTable 中提取你关心的记录,虽然 Select()可以很好的工作,但它还是有一些明显的限制.首先,它是基于字符串的,也就是说可能的错误不能在编译的时候发现.其次,它的过滤功能也很有限,它没有提供 LINQ 操作符能够提供的其他特性,如排序.分组以及投影. 使用 LINQ to DataS

泊学Swift系列之Swift Up and Running——变量和常量

Swift Up and Running——变量和常量 泊学原文 泊学技法视频 当我们学习一门语言的时候,无论是说还是写,也无论是外语或者编程语言,我们都会用自己已经掌握的语言中的元素去理解新语言中对应的部分.学习Swift也一样,作为一种编程语言,它有着和Objective-C,JavaScript或C#等其它编程语言共通的概念和类似的表达方式.如果你或多或少了解过一些编程语言,学习Swift将会是一个非常轻松的过程. Playground Playground是Apple在2014年WWDC

JS中的柯里化(currying)

何为Curry化/柯里化? curry化来源与数学家 Haskell Curry的名字 (编程语言 Haskell也是以他的名字命名). 柯里化通常也称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果.因此柯里化的过程是逐步传参,逐步缩小函数的适用范围,逐步求解的过程. 柯里化一个求和函数 按照分步求值,我们看一个简单的例子 var concat3Words = function (a

我们复习.Net的这些日子里

今天是我们复习前面学习的第三天,也是在今天我们结束了复习.之前上学时间感觉知识全是生僻的,在生活中很少用到,因此喜欢重复的记忆,而现在学习的知识全是现在乃至未来,将是每天我们使用的,所以就感觉没必要重复记忆啦,只要我记得知识点的存在然后会想起来具体的内容的,可是今天的复习我发现这样的做法还是不对的,也可能只是刚开始啦,太多东西都是硬性的,因此我想通过这篇文章来重新捡起来我忘记的,嘿嘿.下面就来说下具体容易忘记的和做起来题还是比较生硬的吧. 一.构造函数 构造函数方法名和类名一样,没有返回值,连v

全局变量、局部变量、静态全局变量、静态局部变量在内存里的区别

一.程序的内存分配 一个由C/C++编译的程序占用的内存分为以下几个部分: 1.栈区(stack)- 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. 2.堆区(heap) - 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 .注意它与数据结构中的堆是两回事,分配方式倒是类似于链表. 3.全局区(静态区)(static)- 全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变

JavaScript的柯里化函数

柯里化,或者说部分应用,是一种函数式编程的技术,对于熟悉以传统方式编写 JavaScript 代码的人来说可能会很费解.但如果使用得当,它可以使你的 JavaScript 函数更具可读性. 更具可读性和灵活性 函数式 JavaScript 被吹捧的优点之一就是拥有短小紧凑的代码风格,可以用最少行数.更少重复的代码得到正确的结果.有时这会以牺牲可读性为代价:如果你还不熟悉函数式编程的方法,这种方法写的代码会很难阅读和理解. 如果之前你遇到过柯里化这个术语,但是不知道它是什么意思,把它当做奇怪的.难