[譯文] 為什么你在 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"?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM