ReSharper 和隐式类型变量

Posted

技术标签:

【中文标题】ReSharper 和隐式类型变量【英文标题】:ReSharper & Implicitly Typed Variables 【发布时间】:2011-10-06 16:52:05 【问题描述】:

我正在使用 ReSharper 帮助我发现代码中可能存在的错误,虽然不是错误,但它一直抱怨我应该使用 var 关键字而不是在声明中显式键入变量。就我个人而言,我认为这对我和任何阅读我的代码的人来说都更加清晰

IList<T> someVar = new List<T>();

而不是

var someVar = new List<T>();

知道两种方式之间没有性能差异,我应该忽略这些提示还是坚持使用 var 关键字?

隐式类型变量只是个人喜好还是一种好习惯?

【问题讨论】:

Use of var keyword in C# 的可能重复项 绝对是品味问题。我喜欢直言不讳。不知道为什么 Resharper 建议您更改。我建议禁用它以保持理智。 相关:***.com/questions/1504064/… Why does ReSharper want to use 'var' for everything?的可能重复 【参考方案1】:

我至少看到两个原因。

首先,这是DRY principle 的问题:不要重复。如果将来您决定将变量类型从List&lt;&gt; 更改为Stack&lt;&gt;LinkedList&lt;&gt;,那么对于var,您必须在一处进行更改,否则您必须在两处进行更改。

第二,泛型类型声明可能会很长。 Dictionary&lt;string, Dictionary&lt;int, List&lt;MyObject&gt;&gt;&gt; 有人吗?这不适用于简单的List&lt;T&gt;,但是对于不同的对象类型,您不应该有两种代码样式。

【讨论】:

【参考方案2】:

这只是风格问题。如果右侧的类型像您的示例中那样立即显而易见,我倾向于支持var,但如果您不喜欢var,则禁用该规则是完全可以的。许多程序员更喜欢显式类型。

查看 Eric Lippert 的博客文章 Uses and misuses of implicit typing,详细讨论何时适合使用 var

【讨论】:

【参考方案3】:

我只在类型声明太长(超过 15 个字符)时使用 var。否则显式声明更具可读性。

要在 Resharper 8.2 中禁用它,请转到 Resharper > 选项 > 代码检查 > 检查严重性 > 语言使用机会。在搜索框中输入“使用”一词有助于过滤列表。

【讨论】:

【参考方案4】:

这主要是编码风格问题(匿名类型除外)。就个人而言,我在编写代码时经常使用 var,但在我完成后使用 ReSharper 的代码清理将它们转换回显式类型。这使我可以更快地编写代码,然后将代码转换为我自己和其他人认为更易读的东西(毕竟代码只写一次,但要读很多次)。

我通过关闭以下“语言机会设置”(可在选项、代码检查、检查严重性中找到)来关闭使用“var”的 ReSharper 提示:

在初始化器显式声明类型时使用“var”关键字。 尽可能使用“var”关键字。

您可以在以下代码清理设置中配置 ReSharper 以将“var”转换为显式类型:

在声明中使用'var'

【讨论】:

【参考方案5】:

这只是简洁的问题,就像自动属性一样。坚持你觉得最舒服的。

【讨论】:

【参考方案6】:

对于初级开发人员来说,这是一个很好的问题。不一定是询问者是初级开发人员,但在向初级开发人员提供信息之前确保澄清是一件好事。

本着这种精神,任何发现这个问题的人都应该始终明白,可读性是少数几个质量属性之一,当然也是早期掌握的最重要的属性之一。可读性包括变量命名实践和显式代码,仅举几例。

也就是说,可读性的一个微观方面是是否通过 var 关键字使用隐式类型。简短的回答是也许。一个有根据的示例回答可能会将也许缩小到很少

所以,为了让这个更容易理解,我将从通过 var 关键字使用隐式输入的原因开始。

(语言视角) 不使用隐式类型的第一个原因是因为 C# 的主要优势在于它是一种强类型语言。有很多很棒的语言,它们的优势包括不是强类型的,比如 javascript。每种语言都是不同的,都有自己的优势/劣势。对于 C#,强类型是其最重要的优势之一。


此答案假定您的代码是可靠的。如果您在遗留代码库中工作,或者是尚未完全专注于依赖注入或 Liskov 替换的初级开发人员,那么微调您的 var 使用不是您现在应该关注的地方.

分配给变量的方法只有几种。这些是我现在想到的:

ISomething someVar = new Concrete(); // <1. Can't use var to create Interfaces.

var someVar = GetFromMethod();   // <-- 2. Taken from return type

var someVar = new MyPerson();    // <-- 3. Custom complex reference type

var someVar = new DateTime();    // <-- 4. Built-in simple Reference Type
var someVar = string.Empty;      // <--      <<

var someVar = new List<T>();     // <-- 5. Built-in complex Reference Type
var someVar = new Dictionary<string, Dictionary<int, List<MyObject>>>();

var someVar = true;              // <-- 6. simple Value type assignment

var someVar = 1;                 // <-- 7. complex Value type assignment(s)
var someVar = 1.0;               // <--      <<
var someVar = 1.0d;              // <--      <<

foreach (var i = 0; i <= . . .)  // <-- 8. Same as 7 above, but different context.

var someVar = new Name = "yo"; // <-- 9. Instantiate Anonymous Type

(细分)

1. 在上述示例的示例 1 中,我仅说明了您只是不能使用 var 关键字的情况。您显然无法在接口下创建具体的实例化。我在#5 中更详细地介绍了使用接口。 不要这里不能使用var

2. 示例 2 假设有人使用与您相同的开发工具,并且每个人都想在阅读代码时花时间研究方法的返回类型。根据您阅读代码或代码审查的速度,这可能是一个微不足道或主要的缺点。 此处不要使用 var

3.你为什么要实例化一个newable in-line?正如我之前所说,这些示例假设您练习 SOLID 原则。这种声明变量的方式会产生代码异味。如果您在代码库中搜索 new 关键字,则唯一的结果应该是自动生成的代码、组合根或下面的 #4。 不要在此处使用 var 永远不要这样做

4. new DateTime(); 和其他一些罕见的内置简单类型是您应该在代码库中看到 new 关键字的罕见情况。在示例 4 中使用 var 关键字并不是什么大问题。但老实说,你在这种情况下努力隐瞒到底是为了什么?字符串的相同问题。 可以在这里使用 var...但是为什么呢?

5.您应该始终尽量使用最不具体的类型。简而言之,这意味着使用小型接口。此规则主要适用于面向外部的 API,因为您希望在不破坏消费者的情况下尽可能灵活地进行更改。这条规则没有严格应用于内部代码的唯一原因是,如果开发人员想要进行重大更改,他们有能力花费额外的时间并做额外的工作来级联中断修复。这不是一个很好的借口。

.....5.1 所以对于第一部分,请注意 someVar 变成了Generic.List&lt;T&gt; 类型。如果您想创建IList 类型的变量,正如我看到的那样,那么使用var 关键字不是您想要的。这通常是用尽可能少的特定类型声明变量的规则。看:IList 与 List。如果您故意不想让变量的使用在List&lt;T&gt; 中包含所有额外的垃圾怎么办?这些规则是有原因的。 如果可以遵循此规则,请尽量不要使用 var 关键字。

.....5.2 假设您不在乎,或者不想按照建议使用接口,这很好。这在某种程度上也适用于长度的概念。如果您有嵌套级别的集合并且您的声明很长,那么没有人会责怪您使用var 关键字。 好的,如果您不使用接口

6. 这与示例 #7 类似,但适用于非数值类型。简单的问题是,“为什么?”正如我在#4 中所说,你要买什么?假设您使用默认值,则无论如何您都必须指定类型。为什么要混合规则,它买了什么? 当然可以,但为什么呢?

E.G.:无论如何,有时你必须明确,为什么要混合规则?:

bool isVarOkay, canUseVar;
char a, b, c, d, e, f;
bool isSample = true;
byte etc;
var isOtherSample = true; //<-- why?

7. 有很多数值类型。大多数原因是为了精确,有些是为了语义目的。无论哪种方式,为什么让编译器猜测你想要什么而不是明确的。如果有明确的时间,数值类型就是时间。就plain-ol int 而言,使用 var 可能有一些余地,因为它是如此直接和明显。但我宁愿把它留到第 8 点。 不要使用 var 关键字

8. 这种代码结构用在很多地方,看起来几乎可以做到。但再一次:为什么,你在保存什么? varint 都是 3 个字符。 当然可以,但为什么呢?

9. 在匿名返回的情况下,您几乎必须使用 var 关键字。不这样做会违背匿名的目的。大多数匿名类型都可以内联,以便它们的结果立即转换为有用的东西,因此不必将它们分配给变量。但是有一些不值得避免的场合。 如有必要,对匿名类型使用 var。


结论

var 关键字对于匿名类型是不可避免的。此外,它对于具有多个泛型级别的泛型类型会有所帮助,这些泛型可以像 Dmitry 的示例 Dictionary&lt;string, Dictionary&lt;int, List&lt;MyObject&gt;&gt;&gt; 那样进行长声明。最后,如果您在数字 4、5、6 和 8 所示的示例中使用 var 关键字,不会伤害任何人的感受。但您并没有购买任何东西。

使用var关键字可以让你改变类型,或者让你坚持DRY原则的想法,不过是一个虚假的借口。只有在极少数情况下,声明的赋值端才正确地表示类型应该是什么。

【讨论】:

以上是关于ReSharper 和隐式类型变量的主要内容,如果未能解决你的问题,请参考以下文章

创建一个自定义属性,提示 Resharper 隐式使用该属性

Resharper 自定义模式变量

Resharper:vars

Resharper:vars

我应该*总是*支持 C# 3.0 中的隐式类型局部变量吗?

如何修复:在闭包 resharper 警告中访问 foreach 变量?