ReSharper为什么要对所有内容都使用'var'?


214

我刚刚开始在Visual Studio中使用ReSharper(在关于SO的许多建议之后)。为了进行试验,我打开了一个最近的ASP.NET MVC项目。我注意到它建议的第一批也是最常见的事情之一是将我的大部分/所有显式声明var改为。例如:

//From This:
MyObject foo = DB.MyObjects.SingleOrDefault(w => w.Id == 1);
//To This:
var foo = DB.MyObjects.SingleOrDefault(w => w.Id == 1);

等,即使采用简单的类型,如intbool

为什么建议这样做?我不是来自计算机科学或.NET背景的人,最近才“涉足” .NET开发,所以我真的很想了解正在发生的事情以及它是否有益。



27
我已经考虑了一段时间,得出的结论是var,即使类型根本不明显,也应该始终使用!原因是因为它迫使我选择我能想到的最具描述性的名称,最终使代码更具可读性。最终,它还有助于将逻辑与实现分开。当然,这只是我的意见,我希望它会对某人有所帮助;)。
2013年

Answers:


189

原因之一是提高了可读性。哪个更好?

Dictionary<int, MyLongNamedObject> dictionary = new Dictionary<int, MyLongNamedObject>();

要么

var dictionary = new Dictionary<int, MyLongNamedObject>();

260
我会说第一个。更容易看到发生了什么!
孟格斯·庞

104
真菌:您喜欢冗余文本冗余文本吗?:D
Mark Simpson

73
在我看来,露骨更清晰。在某些情况下,大量使用var会令人头疼。
user1231231412 2012年

171
我讨厌开发人员使用var所有东西时-我使用TFS(基于Web的差异)进行了大量的代码审查,这使我的工作异常困难:即var items = GetSomeItems();vs vs都IDataReader dr = GetSomeItems();缺少using语句,但是使用IDataReadervs 时更容易理解var
克里斯·盖斯勒

17
如果您是编写出色代码的优秀开发人员,并且使用的是像Resharper这样的库,那么您就不需要知道处理的显式类型。就像当您使用接口声明合同而不是具体类时一样,var允许您说您不在乎返回的“类型”是什么,您只在乎它的作用,并使用命名良好的变量,借助智能感知和重新共享/ VS帮助程序(如CTRL + CLICK导航至定义),您将获得99%的访问率。另外,使用var意味着如果我更改方法返回类型,则不必重写我的代码库。
Joshua Barker 2013年

286

ReSharper的建议显然是过度使用了var关键字。您可以在类型明显的地方使用它:

var obj = new SomeObject();

如果类型不明显,则应将其写出:

SomeObject obj = DB.SomeClass.GetObject(42);

36
扮演魔鬼的拥护者,也许如果方法或变量名的类型不清楚,则表明命名问题多于对var的过度使用。我原则上同意,但是var仅在不消除清晰度时才应使用。
马特·布里格斯

33
在这种情况下,我宁愿使用更好的变量名。基本上,您是在建议我们查找变量的定义位置以找出类型-我是在提议更好地命名变量,以便我们一目了然地了解变量的用途。
哈科·普雷托里乌斯2009年

18
@Jaco:+1,但是值得一提的是,不建议将有关类型的信息放在变量名中。例如,匈牙利表示法不被认为是一种好习惯。
罗曼·布科

8
ReSharper的默认设置是否被过度使用var是一个问题,而不是“清楚地”一件事情或另一件事。我不想输入那些编译器可以自行解决的问题。我喜欢C#类型推断,并且经常希望它与F#类型推断一样好。如果可以的话,我会在方法参数和返回类型中忽略显式类型,就像F#中的规范一样。当然,并非所有人都同意。
乔尔·穆勒

15
@AnonymousType:您仍然缺少重点。您说过,方法名称应始终反映方法的意图,但是即使这样做,也并不意味着该名称指定了返回值的类型。Stream例如Read,用于读取对象的方法命名为ReadAndReturnNumberOfBytesAsInt32
Guffa

99

我个人更喜欢关闭该建议。使用var通常可以提高可读性;但是正如您提到的,有时它会减少它(使用简单类型,或者当结果类型模糊时)。

我宁愿选择何时使用var和不使用。但是,那只是我。


11
我以为ReSharper应该很聪明。知道结果类型何时是显而易见的(例如,带有new关键字的任何内容)以及何时不是显而易见的,这是否足够聪明?
DisgruntledGoat

3
好吧,我不知道该功能的特殊性,但是,我肯定知道我对它所提供的大量建议感到不知所措;而且我也var经常使用。
布赖恩·梅纳德(

5
我发现,当您始终使用var(如resharper建议)时,它将迫使您正确命名变量。
Sauleil'1

您可以关闭建议吗?
克里斯S

@AngeDeLaMort:关键是它迫使您使用不正确的名称fe var methodXYResultIntArray。这违反了所有编码标准,而且不够简洁int[] methodXYResult。如果以后想byte[]从该方法返回a ,则所有变量名都错误。使用显式类型,您可以很容易地重构它。有理由使用var,fe搭配Dictionary<string, List<SomeType<int>>>。但是,如果full-type-name不太长,并且您不在new右侧(或显式强制转换)上使用,则应禁止使用reshaper。
蒂姆·舒默特

69

var可以提高代码的可读性,同时降低对代码的立即理解。一样,它可能会降低其他情况下代码的可读性。有时使用它是中性的。理解的可读性不是成比例的,而是取决于情况。有时两者一起增加或减少。

因素是var要应用的内容,以及目标如何很好地支持其对读者的数据类型的即时混淆,或者是否需要其类型信息来理解手头的程序部分。

例如,错误的命名可能导致var代码理解力下降。但是,这不是var错误:

var value1 = GetNotObviousValue(); //What's the data type? 
//vs. 
var value2 = Math.Abs(-3); // Obviously a numeric data type. 

有时,var在缺少代码的情况下更易读时,使用简单数据类型没有意义:

var num = GetNumber(); // But what type of number?
// vs. 
double num = GetNumber(); // I see, it's a double type. 

有时候var,隐藏不一定要了解以下复杂性的数据类型信息会很有用:

    IEnumerable<KeyValuePair<string,List<Dictionary<int,bool>>>> q = from t in d where t.Key == null select t; // OMG! 
    //vs. 
    var q = from t in d where t.Key == null select t;

    // I simply want the first string, so the last version seems fine.  
    q.First().Key; 

必须使用var时,有一个匿名类型存在,因为没有类型名称通过调用它:

var o = new { Num=3, Name="" };

尽管您有Visual Studio Intellisense仍提供类型信息var,则您无需借助任何帮助即可通过严格的代码阅读来减少对理解的依赖。假设不是每个人都可以拥有或使用Intellisense,这可能是明智的。

综上所述,基于上述示例,我建议对Carte blanche进行应用var并不是一个好主意,因为大多数事情最好适度地进行,并且要根据此处显示的情况来完成。

为什么默认情况下Resharper会全部使用它?我建议您放轻松一点,因为它无法解析情况的细微差别,以决定何时最好不使用它。


5
恕我直言,您的示例实际上是使用的充分理由var,它将迫使您编写体面的方法名称。GetNumber() -but what type?-好,你为什么在乎? 如果知道那么重要,请调用方法GetNumberAsDouble(),那么就很清楚了,如果您有一个方法要返回,string而有一个方法要返回,则可以使用double
nicodemus13 2015年

10
@ nicodemus13通常您会知道,当您真正关心函数的返回类型时,实际上是在使用返回值,而不是在编写函数本身时。您建议的命名方案可能会导致诸如GetResultsAsIEnumerableOfDouble之类的滥用,它所做的全部就是通过使用var将您从分配左侧删除的类型信息移至assignemnt的右侧。
埃里克

var value2 = Math.Abs​​(-3); //显然是数字数据类型。抱歉,我完全不同意这一点,因为Abs方法有7个重载,因此在查看时会导致
模糊不清

var也可能导致细微的逻辑错误,例如:var counter =“ 0”; 当您想要的是整数时。
阿兰妮娜

42

在ReSharper(8.02,但可能是其他版本)中,可以通过首先打开ReSharper的选项菜单将“使用隐式类型的局部变量声明”建议的选项调整为您的首选项,无论采用哪种方式:

ReSharper选项菜单

然后,在“代码检查”下,通过调整所选语言的“检查严重性”,在我的情况下为c#:

关闭隐式类型的局部变量建议

如您所见,有一些选项可以调整ReSharper提出的所有建议。希望这对像我这样已经拥有'var'使用策略并且只希望ReSharper尊重它的人有所帮助:)


这回答了一个根本没有问过的不同问题。
卡莱斯·阿尔科里亚

9
但这与许多到这里来寻找它的人有关。+1
Ori Nachum

24

令我惊讶的是,没有人提到更改实例化对象的类型也更容易,因为

AVeryLongTypeName myVariable = new AVeryLongTypeName( arguments );

是一种重复。如果要更改AVeryLongTypeName为其派生类之一,则在使用时只需更改一次即可,var并且仍然可以访问子类的方法。

除此之外,提高的可读性是重要的一点,但是正如其他人所说,var不应被过度使用,因此我认为在Resharper中关闭提示绝对是可以的。


在调用工厂方法而不是“新方法”时非常有用
Ian Ringrose

如果您在最初编写代码时需要使用“ MyClass”并且它可以工作,那么它就可以工作。当您需要更改它时,您必须去到任何地方更改它,尤其是当涉及接口时。代码不应被视为杂文,而应具有语义性和良好的定义。
Piotr Kula 2016年

24

'var'即将变得清晰

有关是否使用var关键字的主要争论在于代码对您和其他开发人员的可读性。

就像您在写故事一样,也没有确定的正确答案。但是,让我们用通俗易懂的英语来看一些例子。

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

谁走了另一条路?杰克还是比尔?在这种情况下,使用名称“ Jake”和“ Bill”就像使用类型名称。而“他”和“他”就像使用var关键字。在这种情况下,它可能有助于更具体。以下示例更加清晰。

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

在这种情况下,更加具体可以使句子更清楚。但这并非总是如此。在某些情况下,特定性使其难以阅读。

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

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

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

这些示例涵盖了要点,但并不能说明全部内容。在那些例子中,只有一种称呼这个人的方法。通过使用它们的名称或使用更通用的术语(例如“他”和“他”)。

对于代码,我们有3种方法可以帮助增加清晰度。类型,变量名称和赋值。以这行代码为例:

Person p = GetPerson();

现在的问题是,该行代码中是否有足够的信息来帮助您了解正在发生的事情?

接下来的代码行呢?您是否仍然知道p在这种情况下的含义:

var p = GetPerson();

现在怎么样:

var p = Get();

或现在:

var person = Get();

或者这个:

var t = GetPerson();

或这个:

var u = Person.Get();

关键字var在给定情况下是否有效在很大程度上取决于代码的上下文,例如变量,类和方法的命名方式。它还取决于代码的复杂性以及围绕它的其余代码。

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

话虽如此,有时我会视情况而定,我会例外,这就是任何复杂事物的本质,而即使不是复杂事物,软件也不是什么。


1
我最喜欢这个答案,因为var只要知道那行内容,我就不会反对。如果我不知道其他解决方案使用不同域模型返回的方法是什么,我宁愿明确定义该类型,使其更易于阅读。+1
Piotr Kula 2016年

在您返回的类型不明显的所有情况下,我同意您不应该使用var,因为您现在正在忽略有用的信息。

18

我也不喜欢这个。

我不希望这变成关于的使用的争论var,它有其用途,但不应在任何地方使用。

要记住的关键是ReSharper被配置为所需的任何编码标准。

编辑:ReSharper和var


13
经过一年左右的抵抗后,我现在几乎总是使用var。
LiamB

15

我看到了许多正确答案,但没有完整答案。

的确,ReSharper var默认情况下会过度使用。我认为大多数人都同意这一点。var使用时和类型很明显(例如使用new语句时)也更容易阅读。我看到了一篇帖子,展示了如何更新检查严重性以仅显示有关使用的提示var

我曾尝试先在其他帖子上发表评论,以添加在何处设置这些帖子,但是却没有声誉。显然,我也没有声誉发布设置的屏幕截图。

我将解释如何到达那里。

在Visual Studio>主菜单> Resharper>选项>代码编辑> C#>代码样式>声明中的Var用法

  • 对于内置类型使用显式类型
  • 对于简单类型,请在明显时使用'var'
  • 在其他地方使用“ var”

在此处输入图片说明

ReSharper帮助文档:代码语法样式:隐式/显式键入(“ var”关键字)-配置使用“ var”关键字的首选项


在var辩论之外,这应该标记为正确答案,这是一种平衡的方法
Brian Ogden

您能否举例说明如何确定“明显”?


13

我的规则是这样的:

  • 你声明一个基本类型(即bytecharstringint[]double?decimal,等)?->使用类型:

    string myStr = "foo";
    int[] myIntArray = [123, 456, 789];
    double? myDouble = 123.3;
  • 你声明的复杂类型(即List<T>Dictionary<T, T>MyObj)?- >使用var

    var myList = List<string>();
    var myDictionary = Dictionary<string, string>();
    var myObjInstance = new MyObj();

我想不同意,string myStr = "foo";很明显这是一个字符串。我会将您所有的示例都放在var类别中...,以及从使用显式类型的方法返回的声明。但归根结底,您和您的团队对特定项目的感觉更好。
Dean Meehan,

12

我只想指出,在C#编码约定中建议使用“ var”

当变量的类型在赋值的右侧很明显时,或者当精确类型不重要时

因此,这可能就是为什么在ReSharper中默认打开提示的原因。他们还提供了某些情况,在某些情况下,该情况不能立即在同一文档中提高可读性。


当您知道类型来自System.Diagnostics.PerformanceCounter() 何处时,那就太好了-您可以从内置的诊断类中轻松分辨出其性能计数器。但是这里返回什么类型?var thingyMaBob = GetThatSpecialThing(18,null,(MyEnum)2)?没有时钟线索,特别是如果您的解决方案中有超过100个项目。
Piotr Kula 2016年

“建议在变量类型很明显时使用”,以及“它们还提供某些情况,在同一文档的下面,它们不能提高可读性”。老实说,我想我已经错过了你的意思。我的回答与您说的一样。
jose

6

ReSharper建议这样做,var因为它会使对象的创建变得整洁。

比较这两个示例:

StringBuilder bld = new StringBuilder();

var bld = new StringBuilder();

这只是一个简写,应该更容易阅读。

我认为用“ new”显式创建新对象时很好。但是,在您的示例中,如果未正确命名类,则可能并不明显。


6

顺便说一句,ReSharper在“您可能希望将此建议应用于您的代码”与“您的代码已损坏,要我解决它?”之间进行区分。该var关键字是建议类,与喜欢的东西“吊装如果减少筑巢”一起; 您不必遵循它。

您可以通过“选项”对话框或直接通过该警报的弹出菜单来配置其每个警报的烦人程度。您可以降级诸如var建议之类的内容,使其不那么突出,也可以升级诸如“使用扩展方法”警报之类的内容,使其显示为实际错误。



4

Var太神奇了!我遇到过许多开发人员,他们var对动态类型的印象是,不是。它仍然是静态类型的,它只是由编译器决定的。

这是使用var的一些令人惊奇的积极之处

较少键入 var会更短且更易于阅读,例如

Dictionary<int,IList<string>> postcodes = new Dictionary<int,IList<string>>()Yuk。

var postcodes = new Dictionary<int,IList<string>>()\ o / \ o /

更具描述性的变量名 -狭义的变量名,但我认为让变量的可var变性在此发光很重要。由于var是有点模糊,它确实鼓励更多desciptive变量名,而不是让类自己说话。

更少的代码更改 -如果方法调用的返回类型更改。您只需要更改方法调用,而不必更改使用的每个位置。

匿名类型 -匿名类型是一个非常强大的概念,尤其是在WebApi 部分资源领域。没有var,就无法使用它们。

但是,有时明确声明类型很有用,而我发现这在基元或结构中最有用。例如,我个人并不觉得此语法非常有用:

for(var i = 0; i < 10; i++) 
{

}

for(int i = 0; i < 10; i++) 
{

}

完全var取决于个人喜好,但使用确实可以加快您的开发速度并释放整个匿名类型的美好世界。


2

没有技术上的区别,如果使用var,则编译器会隐含该类型。如果您有这样的代码:

var x = 1;

x隐含为一个int,不能为其分配其他任何值。

如果更改变量的类型,则var关键字很有用。然后,您只需进行一项更改即可,而无需进行两项更改:

var x = 1; --> var x = "hello";
int x = 1; --> string x = "hello";

1
@AlexKamburov下面的10行代码无论如何都会中断,与var无关。
user3285954 2015年

1
@ user3285954在某些情况下,var可以隐藏问题,而那时情况可能变得很难看。问题不在于编写代码,而在于可维护性。有人认为使用var可以使它更干净,但我有时将其视为混淆。这接近一场宗教辩论。 brad-smith.info/blog/archives/336 我个人仅将var用于Linq语句和其他声明该类型非常冗长的地方。我认为var是一个很好的补充,人们需要注意Anders Hejlsberg关于引入它的原因的评论。
亚历克斯·坎布罗夫

2

var关键字在C#3.0中引入-它让我们对明确指定我们的类型给忘了。

是否使用并没有真正的区别

MyObject foo = DB.MyObjects.SingleOrDefault(w => w.Id == 1);

要么

var foo = DB.MyObjects.SingleOrDefault(w => w.Id == 1);

除了纯粹的可读性和更少的出错机会。

这似乎是一个陈词滥调的示例,但请说以下内容有助于您的理解:

var myInt = 23;

返回一个int类型,而

var myInt = "23";

返回一个string类型。

MSDN参考


2

指定显式对象类型在某种程度上是多余的。甚至用英语翻译,听起来也很多余:“将类型X的对象放入类型X的变量中”与“将类型X的对象放入变量中”。

但是,使用'var'有其局限性。它防止了以下用法多态性纯美容

假设一条狗延伸了动物;猫扩展了动物类的层次结构:

Animal x = new Dog();
DoStuffWithDog(x as Dog);

x = new Cat();
DoStuffWithCat(x as Cat);

void DoStuffWithDog(Dog d){}
void DoStuffWithCat(Cat c){}

x声明为'var'的相同代码将无法编译

var x = new Dog(); // from this point, x is a Dog
DoStuffWithDog(x as Dog);

x = new Cat(); // cannot assign a Cat instance to a Dog
DoStuffWithCat(x as Cat);

void DoStuffWithDog(Dog d){}
void DoStuffWithCat(Cat c){}

无论如何,回到原始问题,我不使用Resharper,但是我认为这足够聪明,可以检测何时不使用“ var”。:-)


4
不必要的强制转换(带有as)简直太糟糕了。如果您有类似Animal x = new Cat(); DoStuffWithDog(x as Dog); 为什么重用x的内容,则可以将编译错误转换为运行时错误。Dog x = new Dog(),Cat y = new Cat(),没有更多歧义。
Mark Sowul 2013年

强制转换(是否使用“ as”)可能会导致运行时错误。当您知道自己在做什么时,对铸造的“恐惧”是什么?为什么要重用x?这里的例子是说明性的。该示例的目的是说明当引用要是多态的时,使用“ var”如何导致限制。
xtrem 2014年

5
不,它不能:多态与这里发生的情况相反。这试图将类型的对象传递Animal给采用Dog和的方法Cat。多态性是反向:这样可以传递类型的对象DogCat采用一个方法为Animal,例如void Walk(Animal a)Walk(new Cat())Walk(new Dog())
马克Sowul

您不应该以这种方式重用变量,这会导致非常讨厌的错误。在短方法中不太明显,但是当您有15-20行代码时,您会忘记x是什么。不要偷懒:var dog = new Dog(); DoStuff(狗); var cat = new Cat(); DoStuff(cat);
user3285954'4

2
没打架 我对声明变量(隐式或显式)的两种方式都不感兴趣。实际上,我每天最多使用至少一天。我只是强调指出,当您选择隐式(var)方法时,编译器将为您确定最窄的类型。这可能并不总是您想要的。就这样。
xtrem 2015年

2

我认为,var仅当在定义变量的值时立即清楚类型是什么时才应使用。

例:

var s = "string value";

显然,这s是一个string

我相信当变量类型名称非常复杂时也是合适的。

例:

Dictionary<SomeCustomKeyType, Dictionary<AnotherCustomKeyType, List<int>>> dict = new Dictionary<SomeCustomKeyType, Dictionary<AnotherCustomKeyType, List<int>>>();

// This is a little easier to read than the above statement
var dict = new Dictionary<SomeCustomKeyType, Dictionary<AnotherCustomKeyType, List<int>>>();

除了这些方案,我看不到使用会产生任何收益var,但是我可以想到一些可能有害的方案:

例如,其右侧变量值未清楚显示该类型的一次性类型。IDisposable的处置很容易被遗忘

例:

// returns some file writer
var wr = GetWriter();

wr.add("stuff");
wr.add("more stuff");

//...
//...

// Now `wr` needs to be disposed, 
// but there is no clear indication of the type of `wr`,
// so it will be easily overlooked by code writer and code reviewer.

1

'var'在您的代码中添加了一种“动态”元素(尽管代码当然仍然严格输入)。我建议不要在类型不明确的情况下使用它。考虑以下示例:

var bar = GetTheObjectFromDatabase();
bar.DoSomething();

ClassA {
  void DoSomething() {
  //does something
  }
}

ClassB {
  void DoSomething() {
  //does something entirely different
  }
}

如果将GetTheObjectFromDatabase()的返回类型从Type A更改为B,我们将不会注意到,因为这两个类都实现了DoSomething()。但是,该代码现在实际上可以做一些完全不同的事情。

这可能与将不同的内容写入日志一样微妙,因此您可能不会注意到unitl为时已晚。

以下使用var应该总是可以的:

var abc = new Something();

1

对于那些不喜欢不断使用“ var”的用户,您也可以在执行“引入变量”时阻止ReSharper默认使用var。很长一段时间以来,这使我感到沮丧,它始终默认为var,并且每次都在更改它。

这些设置位于“代码编辑”>“ C#”>“代码样式”下

在此处输入图片说明


0

没有技术差异(如eWolf所指出的)。您可以使用其中一个,生成的CLR代码将看起来相同。

我认为主要的好处是,这倾向于迫使您使用更好的变量命名。在您的示例中,对于变量名,'foo'是一个非常差的选择。


0

据JetBrains(ReSharper的作者)称,它们默认情况下鼓励使用var。

他们的网站

使用varC#3.0中引入的隐式类型局部变量(也称为关键字)已变得非常流行,因为它可以提高许多情况下的可读性。默认情况下,ReSharper还鼓励使用var关键字,但是其用法首选项可以灵活配置-例如,您可以选择在特定情况下或在任何地方使用显式类型,ReSharper将帮助您实施首选项。


在哪里可以配置何时需要显式类型声明?
user764754
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.