C#:通过构造函数与实例化为属性分配数据

假设我有一个Album类:

 public class Album { public string Name {get; set;} public string Artist {get; set;} public int Year {get; set;} public Album() { } public Album(string name, string artist, int year) { this.Name = name; this.Artist = artist; this.Year = year; } } 

当我想将数据分配给一个types为Album的对象时,接下来的两种方法有什么区别:

通过构造函数

 var albumData = new Album("Albumius", "Artistus", 2013); 

或者在实例化时

 var albumData = new Album { Name = "Albumius", Artist = "Artistus", Year = 2013 }; 

两种方法都称为构造函数,他们只是调用不同的函数。 此代码:

 var albumData = new Album { Name = "Albumius", Artist = "Artistus", Year = 2013 }; 

是这个等效代码的语法简写:

 var albumData = new Album(); albumData.Name = "Albumius"; albumData.Artist = "Artistus"; albumData.Year = 2013; 

编译后两者是相同的 。 所以如果无参数的构造函数不公开:

 public Album() { } 

那么你根本无法使用对象初始化器。 所以主要的问题不是在初始化对象时使用哪个,而是首先将对象暴露给哪个构造器。 如果该对象公开了两个构造函数(如您的示例中的构造函数),那么可以假设两种方式对构造对象同样有效。

有时候对象不会暴露无参数的构造函数,因为它们需要一定的构造值。 虽然在这种情况下,您仍然可以使用初始值设定语法的其他值。 例如,假设您的对象上有这些构造函数:

 private Album() { } public Album(string name) { this.Name = name; } 

由于无参数构造函数是私有的,所以不能使用它。 但是你可以使用另一个,仍然使用初始化语法:

 var albumData = new Album("Albumius") { Artist = "Artistus", Year = 2013 }; 

编译后的结果将与以下内容相同:

 var albumData = new Album("Albumius"); albumData.Artist = "Artistus"; albumData.Year = 2013; 

对象初始化器很酷,因为它们允许你设置一个类内联。 权衡是你的类不可能是不变的。 考虑:

 public class Album { // Note that we make the setter 'private' public string Name { get; private set; } public string Artist { get; private set; } public int Year { get; private set; } public Album(string name, string artist, int year) { this.Name = name; this.Artist = artist; this.Year = year; } } 

如果这个类是这样定义的,那就意味着在构造完成之后,修改类的内容并不是一个简单的方法。 不变性有好处。 当某些东西是不变的时候,确定它是正确的更容易。 毕竟,如果施工后不能修改,就没有办法做到“错”(一旦你确定它的结构是正确的)。 当你创build匿名类时,比如:

 new { Name = "Some Name", Artist = "Some Artist", Year = 1994 }; 

编译器会自动创build一个不可变的类(也就是说,匿名类在构造之后不能被修改),因为不变性是有用的。 正因为如此,大多数C ++ / Java风格指南经常鼓励使成员成为const (C ++)或final (Java)。 移动部件较less时,更大的应用程序更容易validation。

所有人都说,有些情况下,你想快速修改你的class级结构。 比方说,我有一个工具,我想build立:

 public void Configure(ConfigurationSetup setup); 

我有一个class,有一些成员,如:

 class ConfigurationSetup { public String Name { get; set; } public String Location { get; set; } public Int32 Size { get; set; } public DateTime Time { get; set; } // ... and some other configuration stuff... } 

当我想configuration某些属性组合时,使用对象初始值设定项语法非常有用,但并不是一次性地全部configuration它们 。 例如,如果我只想configurationNameLocation ,我可以这样做:

 ConfigurationSetup setup = new ConfigurationSetup { Name = "Some Name", Location = "San Jose" }; 

这允许我设置一些组合,而不必为每个可能的排列定义一个新的构造函数。

总的来说,我认为让你的类不可变将在很大程度上为你节省大量的开发时间,但是使用对象初始化语法使设置某些configuration排列变得更容易。

第二种方法是C#中的对象初始值设定项

对象初始值设定项可让您在创build时将值分配给对象的任何可访问字段或属性, 而无需显式调用构造函数

第一种方法

 var albumData = new Album("Albumius", "Artistus", 2013); 

明确地调用构造函数,而在第二种方法构造函数调用是隐式的。 使用对象初始值设定项,您也可以省略一些属性。 喜欢:

  var albumData = new Album { Name = "Albumius", }; 

对象初始化器会翻译成如下的东西:

 var albumData; var temp = new Album(); temp.Name = "Albumius"; temp.Artist = "Artistus"; temp.Year = 2013; albumData = temp; 

为什么它使用临时对象(在debugging模式下)由Jon Skeet 在这里回答。

就两种方法的优点而言,如果你不想初始化所有的字段,那么IMO,对象初始值设定器会更容易使用。 就性能差异而言,我不认为会有任何对象初始化程序调用参数less构造函数,然后分配属性。 即使有性能差异,它应该是微不足道的。