{}在C#中创build新对象时的行为如何()
我只注意到,使用{}
而不是()
在构造对象时会得到相同的结果。
class Customer { public string name; public string ID {get; set;} } static void Main() { Customer c1= new Customer{}; //Is this a constructor? Customer c2= new Customer(); //what is the concept behind the ability to assign values for properties //and fields inside the {} and is not allowable to do it inside () //without defining a constructor: Customer c3= new Customer{name= "John", ID="ABC"}; }
{}
在C#中创build新对象时的行为如何()
在C#中有三种直接创build新对象的方法:
-
带有参数列表的简单构造函数调用:
new Foo() // Empty argument list new Foo(10, 20) // Passing arguments
-
具有参数列表的对象初始值设定项
new Foo() { Name = "x" } // Empty argument list new Foo(10, 20) { Name = "x" } // Two arguments
-
没有参数列表的对象初始值设定项
new Foo { Name = "x" }
最后一个forms完全等同于指定一个空的参数列表。 通常它会调用一个无参数的构造函数,但它可以调用一个构造函数,其中所有参数都有默认值。
现在,在我给出的两个对象初始值设定项例子中,我已经设置了Name
属性 – 并且可以设置其他属性/域,甚至不设置属性和域。 所以这三个都是等价的,实际上不传递任何构造参数,也没有指定任何属性/域来设置:
new Foo() new Foo() {} new Foo {}
其中,第一个是最传统的。
()
– 调用无参数的构造函数。
{}
– 应该被用来分配属性。
使用{}
无()
是一个快捷方式,只要有一个无参数的构造函数就会工作。
您可以使用对象初始值设定项以声明方式初始化types对象,而不显式调用该types的构造函数。
https://msdn.microsoft.com/en-us/library/bb397680.aspx
如果types具有默认构造函数,也可以省略调用构造函数。 所以
Customer c1 = new Customer { };
是完全一样的
Customer c1 = new Customer() { };
Customer c1 = new Customer {};
这是一个空的对象初始值设定项。 按照规范 ,对象初始值设定项会调用默认的构造函数,除非你指定了要使用的构造函数。 由于没有完成初始化,它将被编译为使用默认构造函数。
为了回答这个问题,如果在C#中创build一个新的对象时{}
像()
那样操作,我们不得不进行更多的细节。 对于你所关心的所有,结果对象将包含相同的数据,但生成的IL不相同。
下面的例子
namespace SO28254462 { class Program { class Customer { private readonly Foo foo = new Foo(); public string name; public Customer() { } public Customer(string id) { this.ID = id; } public string ID { get; set; } public Foo Foo { get { return this.foo; } } } class Foo { public string Bar { get; set; } } static void Main(string[] args) { Customer c1 = new Customer { }; Customer c2 = new Customer(); Customer c3 = new Customer { name = "John", ID = "ABC", Foo = { Bar = "whatever" } }; Customer c4 = new Customer(); c4.name = "John"; c4.ID = "ABC"; c4.Foo.Bar = "whatever"; Customer c5 = new Customer("ABC") { name = "John", Foo = { Bar = "whatever" } }; Customer c6 = new Customer("ABC"); c6.name = "John"; c6.Foo.Bar = "whatever"; } } }
将编译到这个IL(只有主要的方法,没有优化的Debug)
.method private hidebysig static void Main ( string[] args ) cil managed { // Method begins at RVA 0x2050 // Code size 201 (0xc9) .maxstack 2 .entrypoint .locals init ( [0] class SO28254462.Program/Customer c1, [1] class SO28254462.Program/Customer c2, [2] class SO28254462.Program/Customer c3, [3] class SO28254462.Program/Customer c4, [4] class SO28254462.Program/Customer c5, [5] class SO28254462.Program/Customer c6, [6] class SO28254462.Program/Customer '<>g__initLocal0', [7] class SO28254462.Program/Customer '<>g__initLocal1' ) IL_0000: nop IL_0001: newobj instance void SO28254462.Program/Customer::.ctor() IL_0006: stloc.0 IL_0007: newobj instance void SO28254462.Program/Customer::.ctor() IL_000c: stloc.1 IL_000d: newobj instance void SO28254462.Program/Customer::.ctor() IL_0012: stloc.s '<>g__initLocal0' IL_0014: ldloc.s '<>g__initLocal0' IL_0016: ldstr "John" IL_001b: stfld string SO28254462.Program/Customer::name IL_0020: ldloc.s '<>g__initLocal0' IL_0022: ldstr "ABC" IL_0027: callvirt instance void SO28254462.Program/Customer::set_ID(string) IL_002c: nop IL_002d: ldloc.s '<>g__initLocal0' IL_002f: callvirt instance class SO28254462.Program/Foo SO28254462.Program/Customer::get_Foo() IL_0034: ldstr "whatever" IL_0039: callvirt instance void SO28254462.Program/Foo::set_Bar(string) IL_003e: nop IL_003f: ldloc.s '<>g__initLocal0' IL_0041: stloc.2 IL_0042: newobj instance void SO28254462.Program/Customer::.ctor() IL_0047: stloc.3 IL_0048: ldloc.3 IL_0049: ldstr "John" IL_004e: stfld string SO28254462.Program/Customer::name IL_0053: ldloc.3 IL_0054: ldstr "ABC" IL_0059: callvirt instance void SO28254462.Program/Customer::set_ID(string) IL_005e: nop IL_005f: ldloc.3 IL_0060: callvirt instance class SO28254462.Program/Foo SO28254462.Program/Customer::get_Foo() IL_0065: ldstr "whatever" IL_006a: callvirt instance void SO28254462.Program/Foo::set_Bar(string) IL_006f: nop IL_0070: ldstr "ABC" IL_0075: newobj instance void SO28254462.Program/Customer::.ctor(string) IL_007a: stloc.s '<>g__initLocal1' IL_007c: ldloc.s '<>g__initLocal1' IL_007e: ldstr "John" IL_0083: stfld string SO28254462.Program/Customer::name IL_0088: ldloc.s '<>g__initLocal1' IL_008a: callvirt instance class SO28254462.Program/Foo SO28254462.Program/Customer::get_Foo() IL_008f: ldstr "whatever" IL_0094: callvirt instance void SO28254462.Program/Foo::set_Bar(string) IL_0099: nop IL_009a: ldloc.s '<>g__initLocal1' IL_009c: stloc.s c5 IL_009e: ldstr "ABC" IL_00a3: newobj instance void SO28254462.Program/Customer::.ctor(string) IL_00a8: stloc.s c6 IL_00aa: ldloc.s c6 IL_00ac: ldstr "John" IL_00b1: stfld string SO28254462.Program/Customer::name IL_00b6: ldloc.s c6 IL_00b8: callvirt instance class SO28254462.Program/Foo SO28254462.Program/Customer::get_Foo() IL_00bd: ldstr "whatever" IL_00c2: callvirt instance void SO28254462.Program/Foo::set_Bar(string) IL_00c7: nop IL_00c8: ret } // end of method Program::Main
正如我们所看到的,前两个Customer
初始化已被转换为相同的IL(IL_0001到IL_000c)。 之后,它变得更有趣了:从IL_000d到IL_0041,我们看到创build了一个新对象,并将其分配给不可见的临时variables<>g__initLocal0
并且只有在完成之后,才会将结果值赋给c3
。 这是C#编译器如何实现对象初始值设定项。 当你看看c4
是如何从IL_0042初始化到IL_006a的时候,在实例化对象之后“手动”设置公共属性的区别是显而易见的 – 没有临时variables。
IL_0070直到最后都等同于前面的例子,除了它们使用一个非默认构造函数和对象初始值设定项的组合。 正如你可能期望的那样,它只是像以前一样编译,但是使用指定的构造函数。
长话短说:从C#开发者的angular度来看,结果基本相同。 对象初始化器是简单的语法糖和编译器技巧,可以帮助使代码更易于阅读。 然而,FWIW,得到的IL与手动初始化属性不同。 尽pipe如此,编译器发出的不可见的临时variables的代价在几乎所有的C#程序中都是微不足道的。
没有新版本的C#隐式地创build对象初始化的构造函数
Customer c1= new Customer{};
以上是一样的
Customer c1= new Customer() { };
对象和集合初始化器(C#编程指南)
Customer c1= new Customer{}
– 这是属性的初始化程序。 你可以把它写成:
Customer c1 = new Customer{ name="some text", ID="some id" };
在你的具体情况下,是的,它会产生一个相同的结果,但不是你可能会想的原因。
为了理解结果,假设你有这样的一个类:
class Customer { public string name; public string ID {get; set;} public Customer() { } public Customer(string n, string id) { name = n; ID = id; } }
当你像这样创build它时:
Customer c = new Customer("john", "someID");
你调用第二个构造函数,并告诉你传递这些值的类,并负责做它认为它是构造函数中最好的谎言(在这种情况下,它将使用这些值将它们传递给公共字段)。
当你像这样创build它时:
Customer c = new Customer { name = "john", ID = "someID" };
你自己设置公共字段,并使用空的构造函数。
无论如何,你应该避免使用公共领域,因为这是不安全的。 你不应该让外面的任何人直接修改它们。 而是只使用私人领域,并使用公共属性来pipe理外部访问!
- sortingDirectory.GetFiles()
- 如何在Windows窗体上显示ClickOnce版本号
- 使用.nettestingSMTP
- 我如何得到一个animation的gif在WPF中工作?
- 我怎么能忽略从Git仓库bin和obj文件夹?
- 在Visual Studio解决scheme中更改我的所有项目的目标框架
- RouteLink和ASP.NET MVC中的ActionLink有什么区别?
- .NET中的Windows应用程序中的Thread.Sleepreplace
- 我可以做什么来解决在SQL Server Compact Edition数据库上的LINQ to SQL中的“行未find或更改”exception?