Vas*_*leF 85 c# oop constructor properties
假设我有一个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;
}
}
Run Code Online (Sandbox Code Playgroud)
当我想将数据分配给类型的对象时Album,接下来的两种方法之间有什么区别:
通过构造函数
var albumData = new Album("Albumius", "Artistus", 2013);
Run Code Online (Sandbox Code Playgroud)
或实例化时
var albumData = new Album
{
Name = "Albumius",
Artist = "Artistus",
Year = 2013
};
Run Code Online (Sandbox Code Playgroud)
Dav*_*vid 115
这两种方法都调用构造函数,它们只调用不同的构造函数.这段代码:
var albumData = new Album
{
Name = "Albumius",
Artist = "Artistus",
Year = 2013
};
Run Code Online (Sandbox Code Playgroud)
是这个等效代码的语法简写:
var albumData = new Album();
albumData.Name = "Albumius";
albumData.Artist = "Artistus";
albumData.Year = 2013;
Run Code Online (Sandbox Code Playgroud)
编译后两者完全相同.因此,如果无参数构造函数不公开:
public Album() { }
Run Code Online (Sandbox Code Playgroud)
然后你无论如何都无法使用对象初始化器. 因此,主要问题不是在初始化对象时使用哪个,而是在对象首先暴露的构造函数. 如果对象公开了两个构造函数(如示例中的那个),则可以假设两种方式对于构造对象同样有效.
有时,对象不会公开无参数构造函数,因为它们需要某些构造值.虽然在这种情况下,您仍然可以将初始化程序语法用于其他值.例如,假设您的对象上有这些构造函数:
private Album() { }
public Album(string name)
{
this.Name = name;
}
Run Code Online (Sandbox Code Playgroud)
由于无参数构造函数是私有的,因此您无法使用它.但是你可以使用另一个并仍然使用初始化器语法:
var albumData = new Album("Albumius")
{
Artist = "Artistus",
Year = 2013
};
Run Code Online (Sandbox Code Playgroud)
编译后的结果将与以下内容相同:
var albumData = new Album("Albumius");
albumData.Artist = "Artistus";
albumData.Year = 2013;
Run Code Online (Sandbox Code Playgroud)
sir*_*lot 28
对象初始化器很酷,因为它们允许您设置内联类.权衡是你的班级不能是不可改变的.考虑:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
如果以这种方式定义类,则意味着在构造类之后,实际上没有简单的方法来修改类的内容.不变性有好处.当事情是一成不变的,它是MUCH更容易地确定它是正确的.毕竟,如果它在构造之后无法修改,那么就没有办法让它"错"(一旦你确定它的结构是正确的).创建匿名类时,例如:
new {
Name = "Some Name",
Artist = "Some Artist",
Year = 1994
};
Run Code Online (Sandbox Code Playgroud)
编译器会自动创建一个不可变的类(也就是说,构造后不能修改匿名类),因为不变性就是有用的.大多数C++/Java风格指南通常鼓励成员const(C++)或final(Java)出于这个原因.当移动部件较少时,更大的应用程序更容易验证.
尽管如此,有些情况下您希望能够快速修改班级结构.假设我有一个我想要设置的工具:
public void Configure(ConfigurationSetup setup);
Run Code Online (Sandbox Code Playgroud)
我有一个班级,有很多成员,如:
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...
}
Run Code Online (Sandbox Code Playgroud)
当我想要配置一些属性组合时,使用对象初始化器语法非常有用,但不一定要同时配置所有这些属性.例如,如果我只想配置Name和Location,我可以这样做:
ConfigurationSetup setup = new ConfigurationSetup {
Name = "Some Name",
Location = "San Jose"
};
Run Code Online (Sandbox Code Playgroud)
这允许我设置一些组合,而不必为每个可能的排列定义新的构造函数.
总的来说,我认为让你的类不可变将从长远来看为你节省大量的开发时间,但是使用对象初始化器语法可以更容易地设置某些配置排列.
Hab*_*bib 13
第二种方法是C#中的对象初始化器
通过对象初始值设定项,您可以在创建时将值分配给对象的任何可访问字段或属性,而无需显式调用构造函数.
第一种方法
var albumData = new Album("Albumius", "Artistus", 2013);
Run Code Online (Sandbox Code Playgroud)
显式调用构造函数,而在第二种方法中,构造函数调用是隐式的.使用对象初始化程序,您也可以省略一些属性.喜欢:
var albumData = new Album
{
Name = "Albumius",
};
Run Code Online (Sandbox Code Playgroud)
对象初始化程序将转换为如下内容:
var albumData;
var temp = new Album();
temp.Name = "Albumius";
temp.Artist = "Artistus";
temp.Year = 2013;
albumData = temp;
Run Code Online (Sandbox Code Playgroud)
为什么它使用临时对象(在调试模式下)由Jon Skeet 在这里回答.
就两种方法的优点而言,如果您不想初始化所有字段,IMO,对象初始化器将更容易使用.就性能差异而言,我认为没有任何因为对象初始化器调用参数less构造函数然后分配属性.即使存在性能差异,也应该可以忽略不计.