采取以下代码段:
List<int> distances = new List<int>();
冗余是语言设计者的意图吗?如果是这样,为什么?
采取以下代码段:
List<int> distances = new List<int>();
冗余是语言设计者的意图吗?如果是这样,为什么?
代码看起来冗余的原因是,对于新手程序员来说,它似乎定义了两次相同的东西。但这不是代码正在做的事情。它定义了两个恰好属于同一类型的独立事物。它定义了以下内容:
List<int>
。List<int>
。考虑以下:
Person[] coworkers = new Employee[20];
这里的非冗余更清楚,因为变量和分配的对象是两种不同的类型(如果对象的类型派生自或实现变量的类型,这种情况是合法的)。
这有什么多余的?
List<int> listOfInts = new List<int>():
翻译成英文:(编辑,为澄清一点)
当您考虑它的作用时,并不是很冗长。
当然还有一个替代方案:
var listOfInts = new List<int>();
这里我们使用的是C#的类型推断,因为你是马上给它赋值的,C#可以通过刚刚在堆中创建的对象来判断你想要创建什么类型。
要完全理解 CLR 如何处理类型,我建议阅读CLR Via C#。
你总是可以说:
var distances = new List<int>();
正如其他人所说:var
消除了冗余,但它具有潜在的负面维护后果。我想说它也有潜在的积极维护后果。
幸运的是,Eric Lippert 写的比我更有说服力: http://csharpindepth.com/ViewNote.aspx? NoteID = 63 http://cshapindepth.com/ViewNote.aspx?NoteID=61
因为声明类型不一定与初始化它有任何关系。
我可以声明
List<int> foo;
并留待稍后初始化。那么冗余在哪里?也许它从另一个函数(如 BuildList())接收值。
正如其他人提到的那样,新的 var 关键字可以让您解决这个问题,但是您必须在声明时初始化变量,以便编译器可以判断它是什么类型。
与其认为它是多余的,不如将该构造视为一种功能,以使您可以节省一行。
而不是拥有
列出距离;距离 = 新列表();
c# 让您将它们放在一行中。
一行说“我将使用一个名为distances的变量,它将是 List 类型。” 另一行说“分配一个新列表并调用无参数构造函数”。
是不是太多余了?也许。这样做会给你一些东西,虽然
1 . 将变量声明与对象分配分开。允许:
IEnumerable<int> distances = new List<int>();
// or more likely...
IEnumerable<int> distances = GetList();
2.它允许编译器进行更强大的静态类型检查 - 当您的声明与分配不匹配时给出编译器错误,而不是运行时错误。
编写软件都需要这两者吗?不,有很多语言不这样做,和/或在许多其他方面有所不同。
“医生!我这样做的时候很痛!” - “不要再那样做了”
如果你发现你不需要或不想要 c# 给你的东西,试试其他语言。即使您不使用它们,了解其他人也可以极大地促进您解决问题的方式。如果您确实使用了一个,那就太好了!
无论哪种方式,您都可以找到足够的视角让自己说“我不需要 c# 编译器强制执行的严格静态类型检查。我将使用 python”,而不是抨击 c# 过于多余。
还可以这样做:
var distances = new List<int>();
C# 3.0(对应于 .Net 3.5)的编译器改进消除了一些此类事情。所以你的代码现在可以写成:
var distances = new List<int>();
更新后的编译器在根据语句中的附加信息确定类型方面要好得多。这意味着您需要为赋值或作为泛型的一部分指定类型的实例更少。
话虽如此,仍有一些地方可以改进。其中一些是 API,而一些仅仅是由于强类型的限制。
冗余本身并不是有意的,而是所有变量和字段都需要具有类型声明这一事实的副作用。当您考虑到所有对象实例化也在新表达式中提到类型的名称时,您会得到看起来多余的语句。
现在使用var关键字进行类型推断,可以消除冗余。编译器足够聪明,可以弄清楚。下一个 C++ 也有一个auto关键字可以做同样的事情。
不过,他们引入var的主要原因是针对没有名称的匿名类型:
var x = new {Foo = Bar, Number = 1};
如果您将它与动态类型语言进行比较,它只是“冗余”。它对于多态性和在编译时查找错误很有用。此外,它使代码自动完成/智能感知更容易为您的 IDE(如果您使用一个)。
添加功能支持后,C# 肯定会变得不那么冗长。
静态类型/C语法的历史神器;比较 Ruby 示例:
distances = []
如果读者很清楚类型是什么,请使用 var。
//Use var here
var names = new List<string>();
//but not here
List<string> names = GetNames();
来自微软C# 编程指南
当变量的特定类型在键盘上输入繁琐,或者很明显,或者不增加代码的可读性时,var 关键字也很有用
您的特定示例确实有点冗长,但在大多数方面 C# 相当精简。
我更喜欢这个(C#)
int i;
对此(VB.NET)
Dim i as Integer
现在,您选择的特定示例通常是关于 .NET 的,这有点偏长,但我认为这不是 C# 的错。也许这个问题应该改写为“为什么 .NET 代码如此冗长?”
我看到使用 var 来解决这样的懒惰的另一个问题
var names = new List<string>();
如果您使用 var,则名为“names”的变量的类型为,List<string>,
但您最终只会使用继承的接口之一List<T>.
IList<string> = new List<string>();
ICollection<string> = new List<string>();
IEnumerable<string> = new List<string>();
您可以自动使用所有这些,但是您是否可以考虑在编写代码时想要使用什么接口?
在此示例中, var 关键字不会提高可读性。
在这个问题的许多答案中,作者都像编译器或辩护者一样思考。良好编程的一个重要规则是不要重复自己!
避免这种不必要的重复是 Go 的明确设计目标,例如:
使用declare-and-initialize 构造
foo.Foo* myFoo = new(foo.Foo)
的简单类型派生可以减少口吃 ( )。:=
因为我们沉迷于编译器和编译器错误。