2009-05-14 22 views
27

Tôi đã tự hỏi, cách ưa thích để xây dựng một đối tượng mới trong C# là gì?Cách ưa thích của việc xây dựng các đối tượng trong C# là gì? Các tham số hoặc thuộc tính của trình xây dựng?

Hãy class Person:

public class Person 
{ 
    private string name; 
    private int age; 

    //Omitted.. 
} 

Tôi có nên tạo ra nó để sử dụng:

New Person("name", 24); 

hoặc

New Person() { Name = "name", Age = 24 }; 

Là nó chỉ là vấn đề của hương vị hoặc là có một tốt lý do để sử dụng cái khác?

Tôi có thể tưởng tượng rằng người ta chỉ nên sử dụng các trường bắt buộc trong hàm tạo và các trường tùy chọn không phải là tham số hàm tạo nhưng bằng cách sử dụng các thuộc tính.

Tôi có ở trong đó không?

+2

Đây là phiên bản C# của http://stackoverflow.com/questions/830657 –

Trả lời

39

Cách ưa thích phụ thuộc vào thiết kế của bạn.

Thuộc tính của trình xây dựng dành cho các mục mà đối tượng của bạn yêu cầu để được tạo chính xác. Tức là, bất kỳ thuộc tính nào mà đối tượng cần có để được khởi tạo cần phải có trong hàm khởi tạo (bạn thường không muốn một đối tượng intialized một phần sau khi hàm tạo được gọi trừ khi bạn tạo một nhà máy hoặc mô hình trình xây dựng và constructor bị ẩn khỏi tất cả trừ nhà máy/nhà xây dựng).

Trình intializers thuộc tính tốt nhất cho cấu hình bổ sung sau một hàm tạo được yêu cầu bởi trường hợp sử dụng cụ thể của bạn nhưng không bắt buộc đối tượng được coi là khởi tạo.

Ví dụ: bạn có thể có đối tượng đại diện cho một người. Một người cần tên và tuổi được khởi tạo, nhưng địa chỉ họ đang sống là cấu hình tùy chọn.Vì vậy, tên và tuổi là các tham số hàm tạo và địa chỉ là thuộc tính đọc/ghi.

Person johnDoe = new Person("John Doe", 24) { Address = "42 Adams Street" }; 
+0

đó là một lý do rất tốt đẹp giúp để phân biệt khi áp dụng những gì. Cảm ơn! – Peterdk

+0

Tôi khuyên bạn nên đọc câu trả lời của Marc Gravell (http://stackoverflow.com/a/863064/23234), cung cấp một số kịch bản thay thế mà nhìn vào sử dụng thực tế, nơi quan điểm lý tưởng hơn tôi trình bày không liên quan do các ràng buộc khác. –

2

Cách thứ hai là chỉ đường cú pháp để thiết lập các thuộc tính bằng tay:

Person p = new Person(); 
p.Name = "name"; 
p.Age = 24; 

Bạn cũng không phụ thuộc vào các nhà xây dựng mà có thể không initalize tất cả các thuộc tính bạn muốn thiết lập.

Nếu lớp học của bạn có một hàm tạo yêu cầu hai tham số này, bạn không nhận được xung quanh để gọi rõ ràng hàm tạo đó.

12

Nó thực sự phụ thuộc vào kịch bản. Cách tiếp cận tài sản có rất nhiều tiện lợi, trong đó bạn không phải sao chép các bài tập trong hàm tạo. Hơn nữa, hầu hết các kịch bản ràng buộc dữ liệu như để có thể tạo ra các đối tượng mới, mà chúng thường sử dụng constructor parameterless, vì vậy đó là một lợi thế lớn.

Tuy nhiên, đối với các loại không thay đổi, cách tiếp cận hàm tạo là lựa chọn hợp lý duy nhất. Điều thú vị (có lẽ) các tham số có tên/tùy chọn trong C# 4.0 cho phép một cái gì đó tương tự như đối tượng initalizers cho các loại bất biến - see here.

Phương thức khởi tạo cũng rất phổ biến đối với các khuôn khổ Inversion of Control, vì nó quảng cáo rõ ràng những gì mà lớp cần để hoạt động.

Bạn có thể cần trộn và khớp, nhưng thường có nhiều kiểu thuộc tính hơn kiểu trình tạo.

+2

Có - các trường chỉ đọc chỉ có thể được đặt bằng mã trình xây dựng. – Dario

5

Đặt giá trị trong hàm tạo, làm cho các thuộc tính đó bắt buộc, vì vậy điều này có nghĩa là bạn không thể tạo một cá thể mới, mà không cần cài đặt các thuộc tính đó. Trong một số trường hợp, điều này là thích hợp hơn, trong các trường hợp khác, điều này không thể thực hiện được.

+0

Điều này đúng, mặc dù đối với các cấu trúc, bạn không thể thực hiện cài đặt bắt buộc. – Noldorin

+0

Thật vậy, nhưng đó là bởi vì một cấu trúc là một loại giá trị, và luôn luôn có một giá trị (mặc định), ngay cả khi nó không được khởi tạo. –

0

Những cân nhắc chính của tôi về câu hỏi này là 1) Dữ liệu mà thực thể instantiating sẽ có khi đối tượng được khởi tạo và 2) Lớp cần đóng gói như thế nào? Nếu, một khi được thiết lập, các thuộc tính sẽ không thể thay đổi (ít nhất, do bất kỳ thực thể bên ngoài nào) thì tôi sẽ sử dụng hàm tạo, vì hàm tạo có thể thiết lập bất kỳ thuộc tính chỉ đọc nào cũng như bất kỳ thuộc tính đọc/ghi nào.

Cũng nên nhớ rằng, giống như bất kỳ phương pháp nào khác, Constructor của bạn có thể bị quá tải, vì vậy bạn có thể thiết lập bất kỳ số cách nào để khởi tạo các thuộc tính đó.

Nói chung, tôi sử dụng các hàm tạo, nhưng có những lúc tôi đặt thuộc tính theo cách thủ công thay thế. Sử dụng đúng công cụ cho vấn đề đúng.

7

Tôi luôn làm việc trên cơ sở mà bạn nên chuyển giá trị cho một hàm tạo bắt buộc đối tượng đó tồn tại ở trạng thái hợp lệ.

Trong ví dụ này, bạn có thể nói rằng người mới không thể tồn tại mà không có độ tuổi để có thể được chuyển vào trong contructor.

Nếu bạn làm việc trên cơ sở một đối tượng nên lập mô hình thực thể công việc thì xác định mức tối thiểu cần thiết để làm cho bất kỳ đối tượng nào hợp lệ - cho dù bạn đặt giá trị mặc định hoặc bằng cách truyền giá trị thông qua hàm tạo.

+1

+1: Các đối tượng phải luôn ở trạng thái hợp lệ sau khi xây dựng và sau mỗi lần gọi phương thức, vì vậy các phương thức không phải xác nhận trạng thái của đối tượng riêng của chúng trước khi chạy, chỉ các đối số của chúng. – palm3D

2

Theo ý kiến ​​của tôi, trước tiên bạn nên quyết định điều gì khiến một người trở thành một người. Thuộc tính của một người cho một đối tượng người được thể hiện một cách chính xác là gì. Các yêu cầu tối thiểu cho một người là gì.

Luôn có một hàm tạo với các yêu cầu tối thiểu.

Tôi sẽ chỉ sử dụng trình khởi tạo đối tượng cho các loại không yêu cầu bất kỳ thuộc tính nào được khởi tạo. Do đó constructor mặc định.

Tôi biết rằng trình khởi tạo đối tượng rất thuận tiện. Các cơ chế khác cũng có thể yêu cầu một hàm tạo rỗng trong đối tượng.

Nhưng tôi không nghĩ rằng điều đó có ý nghĩa rất nhiều khi bạn có thể tạo một Người không có tên.

4

Một vài suy nghĩ:

  1. Bạn cần tài sản công cộng sử dụng Initializers Object. Vì vậy, nếu có một cái gì đó bạn không muốn để lộ, bạn phải khởi tạo chúng bằng tham số constructor.

  2. Nếu bạn kiểm tra IL, bạn sẽ thấy Object Initializer không phải là "nguyên tử". Nếu bạn viết mã như thế này (không phải là tôi khuyên, chỉ là ví dụ):

    using (p = New Person() {Name = GetName(), Age = GetAge()}) 
    { 
        //blah, blah 
    } 
    

    Nếu có một ngoại lệ trong GetAge(), bạn sẽ tạo ra một thể hiện của Person trong tình trạng hỏng. Tồi tệ hơn, bạn không bao giờ có thể nhập phạm vi sử dụng và trường hợp đó sẽ không được xử lý như bạn tưởng tượng.

+0

Tôi thích rằng bạn đã chỉ ra rằng nó không phải là nguyên tử. Rõ ràng khi bạn nhìn thấy nó, và tôi không nghĩ rằng tôi muốn viết mã như bạn đã đặt nó, nhưng nếu tôi đã đọc mã của người khác tôi không nghĩ rằng tôi đã chọn nó. –

0

Để cài đặt thuộc tính theo cách thủ công, chúng sẽ phải được khai báo công khai và bạn có thể muốn thành viên của lớp ở chế độ riêng tư. Trong trường hợp đó hàm tạo là cách để đi, hoặc viết các phương thức để nhận/thiết lập chúng hoặc sử dụng một trình truy cập.

0

Tôi có xu hướng thích một hàm tạo rất đơn giản với trình intializers thuộc tính. Tôi tìm thấy nó dẫn đến mã rõ ràng hơn. Dữ liệu duy nhất tôi sẽ chuyển cho hàm tạo là thông tin mà tôi không muốn người dùng của lớp của tôi thay đổi khi lớp được tạo.

0

Vấn đề thực sự xảy ra khi bạn vượt qua đối tượng thông qua các tầng/lớp. Ví dụ bạn tạo một đối tượng người và đi qua một webservice. Các webservice tại một nơi nào đó cố gắng deserialize và cố gắng để nhanh chóng và sau đó bạn có thể nhận được một lỗi nếu có một paramter cần thiết cho các nhà xây dựng! khi webservices đầu tiên tạo một đối tượng và sau đó gán giá trị.

Vì vậy, tôi muốn có một contructor parameterless nếu nó là một datamodel (POCO loại) mà cần phải đi qua các tầng.

Vì các lý do khác, tham số contructor là cách tốt nhất (đối với trường bắt buộc). Đặc biệt là khi cung cấp các lớp như là một iterface cho các đối tượng bên ngoài hoặc hội đồng.

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