2016-11-17 13 views
15

Hãy nói rằng chúng ta có:không được nhận C# cú pháp

class Foo 
{ 
    public int IntPropertyInFoo { get; set; } 

    public Bar BarPropertyInA { get; set; } 
} 

class Bar 
{ 
    public string StringPropertyInBar { get; set; } 
} 

Sau đó, chúng tôi muốn nhanh chóng Foo với một initializer đối tượng:

public static void Main(string[] args) 
{ 
    var foo = new Foo 
    { 
     IntPropertyInFoo = 123, 
     BarPropertyInA = // Ommiting new and type name - why does it compile? 
     { 
      StringPropertyInBar = "something" 
     } 
    }; 
} 

Cú pháp khởi tạo BarPropertyInA baffles tôi, bởi vì biên dịch mã không có cảnh báo và khi chạy, hãy ném NullReferenceException. Tôi không nhận ra cú pháp đó, nhưng nó dường như có cùng tác dụng khi được sử dụng với một trường, chứ không phải là một thuộc tính.

Cách tháo rời mã biên dịch mang này:

.method public hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    // Code size  34 (0x22) 
    .maxstack 3 
    .locals init ([0] class Test.Foo foo) 
    IL_0000: nop 
    IL_0001: newobj  instance void Test.Foo::.ctor() 
    IL_0006: dup 
    IL_0007: ldc.i4.s 123 
    IL_0009: callvirt instance void Test.Foo::set_IntPropertyInFoo(int32) 
    IL_000e: nop 
    IL_000f: dup 
    IL_0010: callvirt instance class Test.Bar Test.Foo::get_BarPropertyInA() 
    IL_0015: ldstr  "something" 
    IL_001a: callvirt instance void Test.Bar::set_StringPropertyInBar(string) 
    IL_001f: nop 
    IL_0020: stloc.0 
    IL_0021: ret 
} // end of method Program::Main 

nào trông giống như:

public static void Main(string[] args) 
{ 
    var foo = new Foo 
    { 
     IntPropertyInFoo = 123 
    }; 

    foo.BarPropertyInA.StringPropertyInBar = "something"; 
} 

Vì vậy, là thế này phải có một số đường cú pháp để khởi tạo các thành viên sở hữu của/lĩnh vực của, với điều kiện là tài sản/trường được khởi tạo trong hàm tạo?

+0

Đó là lý do tại sao tôi luôn tạo các lớp và danh sách khác trong hàm tạo lớp của mình. – Gavin

+1

Nếu bạn có một hàm tạo cho 'Foo' đặt' BarPropertyInA' thành một 'Bar' mới thì điều này cho phép bạn chỉ cần thiết lập thuộc tính' StringPropertyInBar'. Họ đã đi với điều này thay vì một cái gì đó như 'BarPropertyInA.StringPropertyInBar =" một cái gì đó "' – juharr

+0

Tôi tin rằng cùng được thực hiện với các nhà xây dựng mảng và thích. .Net sẽ hàm ý hàm tạo tốt nhất dựa trên bối cảnh của instantiatin – maximdumont

Trả lời

2

Có, đây là một cách viết tắt để khởi tạo các thuộc tính bắt đầu dưới dạng trống thay vì null. Các thuộc tính thu thập .net là một ví dụ điển hình về điều này.

var cmd = new System.Data.SqlClient.SqlCommand() 
{ 
    Parameters = 
    { 
     new System.Data.SqlClient.SqlParameter() { ParameterName = "@p1", Value = "SomValue"} 
    }, 
    CommandText = "select 1 from Table1 where Value = @p1" 
}; 

Nó cũng cho phép bạn khởi tạo giá trị của thuộc tính chỉ đọc.

//compiles and works 
var message = new MailMessage { To = { "[email protected]" } }; 

message = new MailMessage 
{ 
    // won't compile: To is read-only 
    To = new MailAddressCollection { "[email protected]" }, 
}; 

vay khá nhiều nguyên văn từ bài viết này: http://www.codeducky.org/even-concise-c-object-initializers/

New-ít cú pháp initializer phép bạn thực hiện mã của bạn một chút ngắn gọn hơn và sử dụng cú pháp khởi tạo để cấu hình các thuộc tính read-only. Thật vậy, vì hầu hết các thư viện lớp cơ sở và các lớp gói .NET phổ biến đều tuân theo mẫu rỗng trống cho các thuộc tính thu thập, bạn hầu như luôn có thể tận dụng cú pháp mới ít hơn cho chúng. Cuối cùng, việc sử dụng khởi tạo ít mới cũng có nghĩa là bạn được hưởng lợi từ việc đặt lại bất kỳ giá trị mặc định nào mà đối tượng đã được khởi tạo.

Các vấn đề liên quan