我正在使用 ReSharper 来帮助我发现代码中可能存在的错误,虽然不是错误,但它一直在抱怨我应该使用var
关键字而不是在声明中显式键入变量。就个人而言,我认为这对我和任何阅读我的代码的人来说都更清楚,如果我写的话
IList<T> someVar = new List<T>();
代替
var someVar = new List<T>();
知道两种方式之间没有性能差异,我应该忽略这些提示还是坚持使用var
关键字?
隐式类型变量是否只是品味问题还是一种好习惯?
我正在使用 ReSharper 来帮助我发现代码中可能存在的错误,虽然不是错误,但它一直在抱怨我应该使用var
关键字而不是在声明中显式键入变量。就个人而言,我认为这对我和任何阅读我的代码的人来说都更清楚,如果我写的话
IList<T> someVar = new List<T>();
代替
var someVar = new List<T>();
知道两种方式之间没有性能差异,我应该忽略这些提示还是坚持使用var
关键字?
隐式类型变量是否只是品味问题还是一种好习惯?
我至少看到两个原因。
首先,它是DRY 原则的问题:不要重复自己。如果将来您决定将变量类型从 to 更改List<>
为Stack<>
or LinkedList<>
,那么var
您必须在一个地方进行更改,否则您必须在两个地方进行更改。
第二,泛型类型声明可能会很长。Dictionary<string, Dictionary<int, List<MyObject>>>
任何人?这不适用于 simple List<T>
,但是对于不同的对象类型,您不应该有两种代码样式。
这只是风格问题。var
如果右侧的类型像您的示例中那样立即显而易见,我倾向于支持,但如果您不喜欢var
禁用该规则则完全没问题。许多程序员更喜欢显式类型。
查看 Eric Lippert 的博客文章隐式类型的使用和误用,以广泛讨论何时var
合适。
我只在类型声明太长(15+ 个字符)时使用 var。否则显式声明更具可读性。
要在 Resharper 8.2 中禁用它,请转到 Resharper > 选项 > 代码检查 > 检查严重性 > 语言使用机会。在搜索框中输入“使用”一词有助于过滤列表。
这主要是编码风格问题(匿名类型除外)。就个人而言,我在编写代码时经常使用 var,但在我完成后使用 ReSharper 的代码清理将它们转换回显式类型。这使我可以更快地编写代码,然后将代码转换为我自己和其他人认为更易读的东西(毕竟代码只写了一次,但读了很多次)。
我通过关闭以下“语言机会设置”(在选项、代码检查、检查严重性中找到)来关闭使用“var”的 ReSharper 提示:
当初始化显式声明类型时使用 'var' 关键字。
尽可能使用“var”关键字。
您可以在以下代码清理设置中配置 ReSharper 以将“var”转换为显式类型:
在声明中使用 'var'
这只是简洁的问题,就像自动属性一样。坚持你觉得最舒服的。
对于初级开发人员来说,这是一个很好的问题。不一定是询问者是初级开发人员,但在向初级开发人员提供信息之前确保澄清是一件好事。
本着这种精神,任何发现这个问题的人都应该始终明白,可读性是少数几个质量属性之一,当然也是早期掌握的最重要的属性之一。可读性包括变量命名实践和显式代码,仅举几例。
也就是说,可读性的一个微观方面是是否通过var
关键字使用隐式类型。简短的回答是可能。带有示例的有根据的答案可能会将Maybe缩小到Rarely。
因此,为了使这更容易理解,我将从不通过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
在代码库中看到关键字的少数情况。使用var
示例 4 中的关键字没什么大不了的。但老实说,你在这种情况下努力隐瞒到底是为了什么?字符串的相同问题。可以在这里使用 var ......但是为什么呢?
5.你应该总是尽量使用最不具体的类型。简而言之,这意味着使用小型接口。此规则主要适用于面向外部的 API,因为您希望在不破坏消费者的情况下尽可能灵活地进行更改。这条规则没有严格应用于内部代码的唯一原因是,如果开发人员想要进行重大更改,他们有能力花费额外的时间并做额外的工作来级联中断修复。这不是一个很好的借口。
..... 5.1所以对于第一部分,请注意 someVar 变成了 type Generic.List<T>
。如果您想创建一个 type 的变量IList
,正如我所看到的那样,那么使用var
关键字不是您想要的。这通常是用尽可能少的特定类型声明变量的规则。看:IList与List。如果您故意不想让变量的使用包含所有额外的垃圾List<T>
怎么办?这些规则是有原因的。 如果您可以遵循此规则,请尽量不要使用 var 关键字。
..... 5.2假设您不在乎,或者不想按照建议使用接口,这很好。这在某种程度上也适用于长度的概念。var
如果您有嵌套级别的集合并且您的声明很长,那么没有人会因为使用关键字 而责怪您。好的,如果您不使用接口
6.这类似于示例 #7,但适用于非数字值类型。简单的问题是,“为什么?” 正如我在#4 中所说,你要买什么?假设您使用默认值,则无论如何您都必须指定类型。为什么要混合规则,它买了什么?当然可以,但为什么呢?
EG:无论如何,你有时必须明确,为什么要混合规则?:
bool isVarOkay, canUseVar;
char a, b, c, d, e, f;
bool isSample = true;
byte etc;
var isOtherSample = true; //<-- why?
7.有一堆数值类型。大多数原因是为了精确,有些是为了语义目的。无论哪种方式,为什么让编译器猜测你想要什么而不是明确的。如果有明确的时间,数值类型就是时间。就plain-olint
而言,使用 var 可能有一些余地,因为它是如此直接和明显。但我宁愿把它留到第 8 点。不要使用 var 关键字
8.这种代码结构用在很多地方,看起来几乎没问题。但再一次:为什么,你在保存什么? var
并且int
都是3个字符。当然可以,但为什么呢?
9.在匿名返回的情况下,你几乎必须使用 var 关键字。不这样做会违背匿名的目的。大多数匿名类型都可以内联,以便它们的结果立即转换为有用的东西,因此不必将它们分配给变量。但是有一些不值得避免的场合。如有必要,对匿名类型使用 var。
结论
对于匿名类型,var
关键字是不可避免的。此外,它对于具有多个泛型级别的泛型类型很有帮助,这些泛型可以像 Dmitry 的示例那样进行长声明Dictionary<string, Dictionary<int, List<MyObject>>>
。var
最后,如果您使用数字 4、5、6 和 8 所示示例中的关键字,也不会伤害任何人的感受。但您并没有买任何东西。
使用var
关键字可以让你改变类型,或者让你坚持 DRY 原则的想法,只不过是一个虚假的借口。只有在极少数情况下,声明的赋值端才能正确表示类型应该是什么。