为什么 var 会是一件坏事呢?

发布于 2024-07-14 03:34:43 字数 196 浏览 19 评论 0原文

前几天我和同事聊天,听说他们的编码标准明确禁止他们在 C# 中使用 var 关键字。 他们不知道为什么会这样,而我总是发现隐式声明在编码时非常有用。 我在查找变量的类型时从来没有遇到过任何问题(您只需将鼠标悬停在 VS 中的变量上,就可以通过这种方式获得类型)。

有谁知道为什么在 C# 中使用 var 关键字是一个坏主意?

I've been chatting with my colleagues the other day and heard that their coding standard explicitly forbids them to use the var keyword in C#. They had no idea why it was so and I've always found implicit declaration to be incredibly useful when coding. I've never had any problems finding out what type the variable was (you only hover over the variable in VS and you'll get the type that way).

Does anyone know why it would be a bad idea to use the var keyword in C#?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

烛影斜 2024-07-21 03:34:43

.Net 框架设计指南(很棒的书)的作者,于2008 年 11 月建议当类型明显且明确时考虑使用 var

另一方面,如果使用 var 会导致阅读代码时出现歧义,正如 Anton Gogolev 指出的那样,那么最好不要使用它。

在书中(附录 A)中,他们实际上给出了这个例子:

var names = new List<string>(); // good usage of var

string source = GetSource();
var tokens = source.Split(' '); // ok; most developers know String.Split

var id = GetId(); // Probably not good; it's not clear what the type of id is

为了确保可读性不会受到低级开发人员的突发奇想,您的组织可能已经决定您不值得 var并禁止了它。
但遗憾的是,这就像你有一个很好的工具可供使用,但却把它放在一个上锁的玻璃柜里。

在大多数情况下,对简单类型使用 var 实际上有助于提高可读性,而且我们不能忘记,使用 var 也不会带来性能损失。

The writers of the .Net Framework Design Guidelines (awesome book) that came out in November 2008 recommend considering using var when the Type is obvious and unambiguous.

On the other hand, if using var would result in an ambiguity when reading the code, as Anton Gogolev pointed out, then it's better not to use it.

in the book (Annex A), they actually give this example:

var names = new List<string>(); // good usage of var

string source = GetSource();
var tokens = source.Split(' '); // ok; most developers know String.Split

var id = GetId(); // Probably not good; it's not clear what the type of id is

It's possible that, to ensure that readability is not subjected to the whims of lowly developers, your organisation has decided that you were not worthy of var and banned it.
It's a shame though, it's like having a nice tool at your disposal but keeping it in a locked glass cabinet.

In most cases, using var for simple types actually helps readability and we must not forget that there is also no performance penalty for using var.

时光倒影 2024-07-21 03:34:43
var q = GetQValue();

确实是一件坏事。 然而,

var persistenceManager = ServiceLocator.Resolve<IPersistenceManager>();

对我来说完全没问题。

底线是:使用描述性标识符名称,您会相处得很好。

作为旁注:我想知道当不允许使用 var 关键字时,他们如何处理匿名类型。 或者他们根本不使用它们?

var q = GetQValue();

is indeed a bad thing. However,

var persistenceManager = ServiceLocator.Resolve<IPersistenceManager>();

is perfectly fine to me.

The bottomline is: use descriptive identifier names and you'll get along just fine.

As a sidenote: I wonder how do they deal with anonymous types when not allowed to use var keyword. Or they don't use them altogether?

回眸一笑 2024-07-21 03:34:43

在大多数情况下,如果合理使用(即类型和值相同的简单类型初始值设定项),那就没问题。

有时,不清楚您是否通过更改来破坏了东西 - 主要是当初始化类型和(原始)变量类型不同时,因为:

  • 变量最初是基类
  • 变量最初是接口
  • 变量最初是带有隐式转换运算符的另一种类型

在这些情况下,您可能会遇到任何类型解析的麻烦 - 例如:

  • 对于两个竞争类型具有不同重载的方法
  • 对于两个竞争类型定义不同的扩展方法 类型
  • 在其中一种类型上重新声明(隐藏)的
  • 成员泛型类型推断的工作方式不同
  • 运算符解析的工作方式不同

在这种情况下,您可以更改代码的含义,并执行不同的操作。 那么这是一件坏事。

示例:

隐式转换:

static void Main() {
    long x = 17;
    Foo(x);
    var y = 17;
    Foo(y); // boom
}
static void Foo(long value)
{ Console.WriteLine(value); }
static void Foo(int value) {
throw new NotImplementedException(); }

方法隐藏:

static void Main() {
    Foo x = new Bar();
    x.Go();
    var y = new Bar();
    y.Go(); // boom
}
class Foo {
    public void Go() { Console.WriteLine("Hi"); }
}
class Bar : Foo {
    public new void Go() { throw new NotImplementedException(); }
}

In most cases when used sensibly (i.e. a simple type initializer where the type and value are the same), then it is fine.

There are some times when it is unclear that you've broken things by changing it - mainly, when the initialized type and the (original) variable type are not the same, because:

  • the variable was originally the base-class
  • the variable was originally an interface
  • the variable was originally another type with an implicit conversion operator

In these cases, you can get into trouble with any type resolution - for example:

  • methods that have different overloads for the two competing types
  • extension methods that are defined differently for the two competing types
  • members that have been re-declared (hidden) on one of the types
  • generic type inference will work differently
  • operator resolution will work differently

In such cases, you change the meaning of the code, and execute something different. This is then a bad thing.

Examples:

Implicit conversion:

static void Main() {
    long x = 17;
    Foo(x);
    var y = 17;
    Foo(y); // boom
}
static void Foo(long value)
{ Console.WriteLine(value); }
static void Foo(int value) {
throw new NotImplementedException(); }

Method hiding:

static void Main() {
    Foo x = new Bar();
    x.Go();
    var y = new Bar();
    y.Go(); // boom
}
class Foo {
    public void Go() { Console.WriteLine("Hi"); }
}
class Bar : Foo {
    public new void Go() { throw new NotImplementedException(); }
}

etc

故事未完 2024-07-21 03:34:43

这当然是一个错误。 这是因为有些人没有意识到它实际上是强类型的,并且根本不像 VB 中的 var。

并非所有的公司编码标准都有意义,我曾经在一家公司工作过,该公司希望在所有类名称前加上公司名称前缀。 公司更名后进行了大规模的返工。

Surely this is a mistake. It's because some folk don't realise that it is actually strongly typed, and not at all like a var in VB.

Not all corporate coding standards make sense, I once worked for a company who wanted to prefix all class names with the company name. There was a massive rework when the company changed it's name.

岁吢 2024-07-21 03:34:43

首先,作为一般规则,编码标准应该由团队讨论和同意,并且应该写下它们背后的推理,以便任何人都可以知道它们为什么存在。 它们不应该是来自一位明师的神圣真理。

其次,这条规则可能是合理的,因为代码读取的次数多于写入的次数var 加快写入速度,但可能会减慢读取速度。 显然,这不是像“始终初始化变量”这样的代码行为规则,因为两种替代方案(编写 var 和编写类型)具有完全相同的行为。 所以这不是一条关键规则。 我不会禁止 var,我只会使用“Prefer...”

First, as a general rule, coding standards should be discussed and agreed by the team, and the reasoning behind them should be written down, so that anyone can know why they are there. They shouldn't be the Holy Truth from One Master.

Second, this rule is probably justified because code is more times read than written. var speeds up the writing, but may slow down the reading a bit. It's obviously not a code behaviour rule like "Always initialize variables" because the two alternatives (writing var and writing the type) have exactly the same behaviour. So it's not a critical rule. I wouldn't forbid var, I would just use "Prefer..."

我做我的改变 2024-07-21 03:34:43

您可能认为 Microsoft 的观点是相关的,因为 C# 是他们的语言:

“但是,使用 var 确实至少有可能使其他开发人员更难以理解您的代码。因此,C# 文档通常使用 var仅在需要时才使用。”

请参阅 MSDN - 隐式类型局部变量(C# 编程指南) ),最后一段。


您还应该注意 var 删除了初始分配的编译时数据类型测试。

var x = "mistake";     // error not found by compiler
int x = "mistake";     // error found

由于大多数变量仅分配一次,因此一致使用 var 消除了几乎所有对变量分配的数据类型测试。

这使得您的代码容易受到意外更改的影响,例如合并工具或疲惫的开发人员所做的更改。

You may consider Microsoft's opinion to be relevant, since C# is their language:

"However, the use of var does have at least the potential to make your code more difficult to understand for other developers. For that reason, the C# documentation generally uses var only when it is required."

See MSDN - Implicitly Typed Local Variables (C# Programming Guide), last paragraph.


You should also be aware that var removes the compile-time datatype test on the initial assignment.

var x = "mistake";     // error not found by compiler
int x = "mistake";     // error found

Since most variables are only assigned once, consistent use of var removes almost all datatype tests on variable assignments.

This makes your code vulnerable to accidental changes e.g. those made by merge tools or tired developers.

硬不硬你别怂 2024-07-21 03:34:43

几个月前我写了一篇关于这个主题的博客文章。 对我来说,我会尽可能地使用它,并围绕类型推断专门设计我的 API。 我使用类型推断的基本原因是

  1. 它不会降低类型安全性
  2. 它实际上会通过提醒您隐式强制转换来提高代码中的类型安全性。 foreach 语句中的最佳示例
  3. 保持了 C# 中的 DRY 原则。 这是专门针对申报案件的,何必把名字说两遍呢?
  4. 在某些情况下,这是完全必需的。 匿名类型示例
  5. 更少的输入,但不损失功能。

http://blogs.msdn .com/jaredpar/archive/2008/09/09/when-to-use-type-in​​ference.aspx

I wrote a blog article on this topic a few months ago. For me, I use it every where possible and specifically design my APIs around type inference. The basic reasons I use type inference are

  1. It does not reduce type safety
  2. It will actually increase type safety in your code by alerting you to implicit casts. The best example in the foreach statement
  3. Maintains DRY principles in C#. This is specifically for the declaration case, why bother saying the name twice?
  4. In some cases it's flat out required. Example anonymous types
  5. Less typing with no loss of functionality.

http://blogs.msdn.com/jaredpar/archive/2008/09/09/when-to-use-type-inference.aspx

叫嚣ゝ 2024-07-21 03:34:43

var 是最新的“如何布置大括号”/匈牙利表示法/驼峰式大小写争论。 没有正确的答案,但有人采取极端的态度。

你的朋友很不幸,他们在一名极端分子手下工作。

var is the latest "how to lay out your braces"/hungarian notation/Camel casing debate. There is no right answer, but there are people who sit at the extremes.

Your friend is just unfortunate they work below one of the extremists.

爱的故事 2024-07-21 03:34:43

完全禁止它意味着禁止使用匿名类型(当您更多地使用 LINQ 时,匿名类型会变得非常有用)。

这是简单明了的愚蠢行为,除非有人能给出一个永远不使用匿名类型的充分理由。

Forbidding it entirely means forbidding the use of anonymous types (which become incredibly useful as you use LINQ more).

This is stupidity plain and simple unless someone can formalise a good reason to never use anonymous types.

沧桑㈠ 2024-07-21 03:34:43

用简单英语理解“var”

我将向您展示,使用和不使用“var”都是为了清晰地沟通。

我将展示使用“var”使代码更易于阅读的示例,以及使用 var 使事情难以理解的其他示例。

不仅如此,您还会发现“var”的清晰程度在很大程度上取决于您对代码中其他所有内容的命名。

举个例子:

杰克向比尔打招呼。 他不喜欢他,所以转身走了另一条路。

谁走了另一条路? 杰克还是比尔? 在这种情况下,“Jake”和“Bill”就像类型名称。 而“He”和“him”就像var关键字。 在这种情况下,说得更具体可能会有所帮助。 下面的例子就更清楚了。

杰克向比尔打招呼。 杰克不喜欢比尔,所以他转身走了另一条路。

在这种情况下,更具体可以使句子更清晰。 但情况并非总是如此。 在某些情况下,具体化会使阅读变得更加困难。

比尔喜欢读书,所以比尔去了图书馆,比尔拿出一本比尔一直喜欢的书。

在这种情况下,如果我们使用“he”并且在某些情况下将他的名字全部省略,那么阅读句子会更容易,这相当于使用 var 关键字。

比尔喜欢读书,所以他去图书馆拿出了一本他一直喜欢的书。

这些类比涵盖了要点,但并没有讲述整个故事。 在这些例子中看到只有一种方式来指代这个人。 要么用他们的名字,例如比尔,要么用更笼统的方式,如“他”和“他”。 但我们只用一个词。

对于代码,您有两个“单词”:类型和变量名称。

Person p = GetPerson();

现在的问题是,是否有足够的信息可以让您轻松确定 p 是什么? 您是否仍然知道这种情况下的人是什么:

var p = GetPerson();

这个怎么样:

var p = Get();

这个怎么样:

var person = Get();

或者这个:

var t = GetPerson();

或者这个:

var u = Person.Get();

关键字 var 在给定场景中是否有效很大程度上取决于代码的上下文,例如变量、类和方法的名称,以及代码的复杂性。

我个人喜欢使用 var 关键字,它对我来说更全面。 但我也倾向于根据类型命名我的变量,这样我就不会真正丢失任何信息。

也就是说,有时我会做出例外,这就是任何复杂事物的本质,而软件如果不复杂就什么都不是。

Understanding 'var' in Plain English

I'm going to show you that using AND not using 'var' is about communicating clearly.

I'm going to show examples of cases where using 'var' makes the code easier to read, and other examples when using var makes things hard to understand.

More than that you'll see that how clear 'var' is depends a lot on what you name everything else in your code.

Take this example:

Jake said hello to Bill. He didn't like him so he turned and went the other way.

Who went the other way? Jake or Bill? In this case "Jake" and "Bill" are like the type name. And "He" and "him" are like the var keyword. In this case it might help to be more specific. The following for example is much clearer.

Jake said hello to Bill. Jake didn't like Bill so he turned and went the other way.

In this case being more specific made the sentence clearer. But that's not always going to be case. In some cases being specific makes it harder to read.

Bill likes books, so Bill went to the library and Bill took out a book that Bill has always liked.

In this case it would be easier to read the sentence if we used "he" and in some cases left out his name all together, this is the equivalent of using the var keyword.

Bill likes books, so he went to the library and took out a book that he has always liked.

Those analogies cover the gist, but they don't tell the whole story. See in those examples there was only one way to refer to the person. Either with their name, for example Bill, or by a more general way, like "he" and "him". But we're only working with one word.

In the case of the code you have two "words", the type and the variable name.

Person p = GetPerson();

The question now becomes is there enough information there for you to easily determine what p is? Would you still know what people is in this scenario:

var p = GetPerson();

How about this one:

var p = Get();

How about this one:

var person = Get();

Or this one:

var t = GetPerson();

Or this one:

var u = Person.Get();

Whether the keyword var works in a given scenario depends a lot on the context of the code, like what the names of the variables, classes, and methods are, as well as the complexity of the code.

Personally I like to use the var keyword it's more comprehensive to me. But I also tend to name my variables after the type so I'm not really losing any information.

That said sometimes I make exceptions, such is the nature of anything complex, and software is nothing if not complicated.

陈独秀 2024-07-21 03:34:43

如果滥用,可能会损害可读性。 然而,完全禁止它有点奇怪,因为如果没有它,你的同事将很难使用匿名类型。

It can hurt readability if it is misused. However completely forbidding it is a bit strange as your colleagues will have a tough time using anonymous types without it.

雪花飘飘的天空 2024-07-21 03:34:43

这确实是代码的可读性问题。

我个人的偏好是仅对匿名类型使用“var”(事实上,如果您想使用匿名类型,则需要使用 var),并且这些大多来自 LINQ 查询。 在这些情况下,如果您的查询投影到新的(隐式和匿名)类型,您别无选择,只能使用 var。

然而,C# 3.0 很乐意让您在 LINQ 和匿名类型之外的任何地方使用 var,例如:

var myint = 0;
var mystring = "";

是完全有效的,并且 myint 和 mystring 将通过用于初始化它们的推断值进行强类型化。 (因此,myint 是 System.Int32,mystring 是 System.String)。 当然,当查看用于初始化变量的值时,它们将被隐式类型化为什么类型,这是相当明显的,但是,我认为如果将上面的内容写为:

int myint = 0;
string mystring = "";

因为您可以立即看到, 那么代码的可读性会更好这些变量到底是什么类型。

考虑这个有点令人困惑的场景:

var aaa = 0;
double bbb = 0;

完全有效的代码(如果有点不传统),但在上面,我知道 bbb 是一个 double,尽管初始化值看起来是一个 int,但 aaa 绝对不会是一个 double,而是一个 double国际。

This is really a readability issue with your code.

My personal preference is to only ever use "var" for anonymous types (indeed, if you wish to use anonymous types at all, you'll need to use var), and these mostly come from LINQ queries. In these cases, you have no choice but to use var if your query is projecting into a new (implicit & anonymous) type.

However, C# 3.0 will happily let you use var anywhere you like, outside of LINQ and anonymous types, for example:

var myint = 0;
var mystring = "";

is perfectly valid, and myint and mystring will be strongly-typed by the inferred values used to initialize them. (thus, myint is a System.Int32 and mystring is a System.String). Of course, it's fairly obvious when looking at the values used to initialize the variables what types they will be implicitly typed to, however, I think it's even better for code readability if the above were written as:

int myint = 0;
string mystring = "";

since you can see immediately at a glance exactly which type those variables are.

Consider this somewhat confusing scenario:

var aaa = 0;
double bbb = 0;

Perfectly valid code (if a little unconventional) but in the above, I know that bbb is a double, despite the initializing value appearing to be an int, but aaa will definitely not be a double, but rather an int.

揪着可爱 2024-07-21 03:34:43

来自声明冗余部门(来自Jeff的编码恐怖):

“我使用隐式变量类型
无论何时何地它都会生成我的代码
更简洁。 任何可以去除的东西
我们的代码的冗余应该是
积极追求——直至和
包括切换语言。”

我自己认为这值得考虑,但是制定一个关于何时使用或不使用的全面指南将矫枉过正

From Department of Declaration Redundancy Department (from Jeff's Coding Horror):

"I use implicit variable typing
whenever and wherever it makes my code
more concise. Anything that removes
redundancy from our code should be
aggressively pursued -- up to and
including switching languages."

I myself think it is worth taking about, but creating a comprehensive guideline on when to use or not would be overkill.

凉月流沐 2024-07-21 03:34:43

从 c# 9.0 开始,我们并不真正需要 var。

我们可以简单地

Dictionary<string, List<int>> field = new();

显式类型和短初始化。

as of c# 9.0 we don't really need var.

we can simply

Dictionary<string, List<int>> field = new();

explicit type and short init.

新雨望断虹 2024-07-21 03:34:43

隐式类型很棒,而断然禁止它的人会损害生产力并导致脆弱的代码。

它几乎就像类型安全、编译器检查的鸭子类型,这在重构时非常有用。 例如,如果我有一个返回 List 的方法,并且我将其重构为返回 IEnumerable,则该方法的任何调用者使用 var 关键字并且仅使用 IEnumerable 方法都可以。 如果我已明确指定(例如 List),那么我必须在各处将其更改为 IEnumerable。

显然,如果任何隐式类型调用者需要 List 方法,那么我在构建时会收到编译错误,但如果是这种情况,我可能无论如何都不应该更改返回类型。

Implicit typing is great, and people who flat-out prohibit it damage productivity and invite brittle code.

It's almost like type-safe, compiler-checked duck typing, which is incredibly useful when refactoring. For example, if I have a method which returns a List, and I refactor it to return IEnumerable, then any callers to that method which have used the var keyword and only use IEnumerable methods will be fine. If I've explicitly specified, e.g., List, then I've got to go and change that to IEnumerable everywhere.

Obviously, if any of the implicit-typing callers require List methods, then I'll get compile errors when I build, but if that's the case I probably shouldn't have been changing the return type anyway.

千纸鹤 2024-07-21 03:34:43

Eric Lippert 求和it up well

  • 必要时使用 var; 当您使用匿名类型时。
  • 当声明的类型从初始化器中显而易见时使用 var,特别是当它是一个对象创建时。 这消除了冗余。
  • 如果代码强调变量的语义“业务目的”并淡化其存储的“机械”细节,请考虑使用 var。
  • 如果需要正确理解和维护代码,请使用显式类型。
  • 无论是否使用“var”,都使用描述性变量名称。 变量名应该代表变量的语义,而不是其存储的细节; “decimalRate”不好; “利率”很好。

我自己的观点:我发现诸如 intstringbool 甚至 之类的类型更难阅读并且有点毫无意义用户。 毕竟,它与可读性有关(除了与 LINQ 一起使用的情况),因此当变量散布时,它可能会更难以阅读,并且违背了语言设计者想要的关键字的目的。

Eric Lippert sums it up well:

  • Use var when you have to; when you are using anonymous types.
  • Use var when the type of the declaration is obvious from the initializer, especially if it is an object creation. This eliminates redundancy.
  • Consider using var if the code emphasizes the semantic "business purpose" of the variable and downplays the "mechanical" details of its storage.
  • Use explicit types if doing so is necessary for the code to be correctly understood and maintained.
  • Use descriptive variable names regardless of whether you use "var". Variable names should represent the semantics of the variable, not details of its storage; "decimalRate" is bad; "interestRate" is good.

My own opinion: I find it harder to read and a bit pointless with types such as int, string, bool or even a User. It's about readability after all (except where using it with LINQ), so when vars are splattered about it can be harder to read and defeating the purpose of the keyword that the language designers intended it for.

把人绕傻吧 2024-07-21 03:34:43

我曾经遇到过使用 var 导致类型属于某个基类而不是实际 DataRow 类型的情况(当我 foreach 遍历 Table.Rows 集合时)。 那是我唯一一次遇到 var 的麻烦。

I have had cases (when I foreach through a Table.Rows collection) when using var resulted in the type being of some base class rather than the actual DataRow type. That is the only time I have had trouble with var.

久而酒知 2024-07-21 03:34:43

以下是我对 var 与显式键入的效率进行的测试的结果:

  private void btnVar_Click(object sender, EventArgs e)
    {
        Stopwatch obj = new Stopwatch();
        obj.Start();
        var test = "Test";
        test.GetType();
        obj.Stop();
        lblResults.Text = obj.Elapsed.ToString();
    }

    private void btnString_Click(object sender, EventArgs e)
    {
        Stopwatch obj = new Stopwatch();
        obj.Start();
        string test = "Test";
        obj.Stop();
        lblResults.Text = obj.Elapsed.ToString();

    }

第一个标签结果是:00:00:00 000034

第二个标签结果是:00:00:00 00008

Here are the results of a test I ran on efficiency of var versus explicit typing:

  private void btnVar_Click(object sender, EventArgs e)
    {
        Stopwatch obj = new Stopwatch();
        obj.Start();
        var test = "Test";
        test.GetType();
        obj.Stop();
        lblResults.Text = obj.Elapsed.ToString();
    }

    private void btnString_Click(object sender, EventArgs e)
    {
        Stopwatch obj = new Stopwatch();
        obj.Start();
        string test = "Test";
        obj.Stop();
        lblResults.Text = obj.Elapsed.ToString();

    }

First Label result is: 00:00:00 000034

Second Label result is: 00:00:00 00008

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文