Trường công cộng so với thuộc tính tự động


353

Chúng ta thường nói rằng chúng ta nên bảo vệ việc đóng gói bằng cách tạo các phương thức getter và setter (thuộc tính trong C #) cho các trường lớp, thay vì đưa các trường ra thế giới bên ngoài.

Nhưng có nhiều khi một trường chỉ ở đó để giữ một giá trị và không yêu cầu bất kỳ tính toán nào để có được hoặc đặt. Đối với những điều này, tất cả chúng ta sẽ làm số này:

public class Book
{
    private string _title;

    public string Title
    {
          get{ return _title;  }
          set{ _title = value; }
    }
}

Chà, tôi có một lời thú nhận, tôi không thể chịu viết tất cả những điều đó (thực sự, nó không phải viết nó, nó phải nhìn vào nó), vì vậy tôi đã đi lừa đảo và sử dụng các lĩnh vực công cộng.

Sau đó, đến C # 3.0 và tôi thấy họ đã thêm các thuộc tính tự động:

public class Book
{
    public string Title {get; set;} 
}

cái nào gọn gàng hơn, và tôi biết ơn vì điều đó, nhưng thực sự, có gì khác so với việc tạo ra một lĩnh vực công cộng?

public class Book
{
    public string Title;
}


6
Tôi đã chuyển đổi một điểm yếu thành một tài sản chỉ để tôi có thể thiết lập một điểm dừng trên setter
Ian Ringrose

1
Tôi có xu hướng làm cho bất cứ thứ gì không phải là tài sản riêng tư bởi vì nhận ra rằng tôi phải tái cấu trúc một lĩnh vực thành một tài sản đã dẫn đến một số đau đầu không cần thiết. Thuộc tính, trường và phương thức. Ôi trời! gọi ra một sự không tương thích đã cắn tôi trong quá khứ.
Steven Wexler

2
Các propđoạn mã làm cho nó nhanh chóng để tạo ra tài sản. Chỉ cần gõ proprồi tab.
Tono Nam

Câu trả lời:


175

Trong một câu hỏi liên quan tôi đã có một thời gian trước đây, có một liên kết đến một bài đăng trên blog của Jeff, giải thích một số khác biệt.

Thuộc tính so với biến công khai

  • Sự phản chiếu hoạt động khác nhau trên các biến so với các thuộc tính, vì vậy nếu bạn dựa vào sự phản chiếu, việc sử dụng tất cả các thuộc tính sẽ dễ dàng hơn.
  • Bạn không thể databind chống lại một biến.
  • Thay đổi một biến thành một tài sản là một thay đổi đột phá. Ví dụ:

    TryGetTitle(out book.Title); // requires a variable

24
"Thay đổi một biến thành một tài sản là một thay đổi đột phá." Điều này tất nhiên chỉ áp dụng khi viết một thư viện có thể sử dụng lại, điều mà hầu hết các nhà phát triển không làm.
Steven

30
Ngoài ra, các thuộc tính, thậm chí các thuộc tính tự động, có thể là ảo, trong đó các trường không thể. Vì vậy, một lớp cơ sở có thể có một triển khai trường sao lưu đơn giản do trình biên dịch tạo ra để tự động chống đỡ, trong khi các lớp dẫn xuất có thể thực hiện xác nhận bổ sung hoặc logic / tính toán khác.
KeithS

28
Ngoài ra một trường là một biến và có thể được truyền bằng tham chiếu ( refhoặc outtừ khóa), trong khi một thuộc tính là một cặp truy cập và không thể được chuyển qua tham chiếu. Ví dụ bool success = TryGetMyTitle(out myBook.Title);, sử dụng outsẽ làm việc với một lĩnh vực và không làm việc với một tài sản. Đây là một ví dụ rõ ràng về lý do tại sao sự thay đổi từ lĩnh vực này sang tài sản là một sự thay đổi đột phá!
Jeppe Stig Nielsen

2
@KyleBaran Không, nó không có ý nghĩa nhiều vì một thuộc tính là một cặp phương thức truy cập, không phải là một biến. Một điều thông thường cần làm là khai báo một biến cục bộ (có thể đọc thuộc tính và đặt giá trị của nó vào biến cục bộ), truyền biến cục bộ là ref/ out, sau đó đặt thuộc tính thành giá trị của biến cục bộ sau đó. Nhưng sau đó phương thức được gọi không tự truy cập vào thuộc tính, nó truy cập vào biến cục bộ mà bạn đã thực hiện ở đó.
Jeppe Stig Nielsen

5
@theberserker Đúng, mặc dù trong C # 6, bạn có thể làm điều public int Foo { get; }đó sẽ tạo ra một thuộc tính tự động với trường sao lưu chỉ đọc.
Michael Stum

83

Bỏ qua các vấn đề API, điều tôi thấy có giá trị nhất khi sử dụng một thuộc tính là gỡ lỗi.

Trình gỡ lỗi CLR không hỗ trợ các điểm ngắt dữ liệu (hầu hết các trình gỡ lỗi gốc đều làm). Do đó, không thể đặt điểm dừng trên đọc hoặc ghi của một trường cụ thể trên một lớp. Điều này là rất hạn chế trong các kịch bản gỡ lỗi nhất định.

Vì các thuộc tính được triển khai như các phương thức rất mỏng, nên có thể đặt các điểm dừng trên đọc và ghi các giá trị của chúng. Điều này mang lại cho họ một chân lớn lên trên các lĩnh vực.


2
Mười năm sau, các điểm dừng dữ liệu ở đây, ít nhất là cho .NET Core :)
Luaan

72

Thay đổi từ một trường thành một tài sản phá vỡ hợp đồng (ví dụ: yêu cầu tất cả các mã tham chiếu được biên dịch lại). Vì vậy, khi bạn có một điểm tương tác với các lớp khác - bất kỳ thành viên nào (và thường được bảo vệ), bạn muốn lập kế hoạch cho sự phát triển trong tương lai. Làm như vậy bằng cách luôn luôn sử dụng các thuộc tính.

Không có gì để biến nó thành một tài sản tự động ngày hôm nay, và sau 3 tháng, nhận ra rằng bạn muốn làm cho nó trở nên lười biếng và đặt một kiểm tra null trong getter. Nếu bạn đã sử dụng một trường, đây là một thay đổi biên dịch lại tốt nhất và không thể ở mức tồi tệ nhất, tùy thuộc vào ai & những gì khác phụ thuộc vào hội đồng của bạn.


9
Tôi thích Câu trả lời này vì nó không sử dụng các từ 'phản chiếu', 'giao diện' hoặc 'ghi đè'. (quá tệ về 'hợp đồng')

65

Chỉ vì không ai đề cập đến nó: Bạn không thể xác định các trường trên Giao diện. Vì vậy, nếu bạn phải triển khai một giao diện cụ thể xác định các thuộc tính, các thuộc tính tự động đôi khi là một tính năng thực sự tốt.


1
Tôi sẽ nói rằng nếu bạn cần một giao diện xác định các thuộc tính, thì nó phải là một lớp trừu tượng. Chỉ vì c # cho phép bạn xác định các thuộc tính trong giao diện, không có nghĩa là bạn nên sử dụng chúng. Đó là thiết kế xấu.
Odys

8
@odyodyodys - Tôi không chắc là tôi đồng ý rằng đây là thiết kế tồi. Hãy giải thích lý do của bạn?
Zaid Masud

4
@odyodyodys Tôi đồng ý với zooone9243: Imp, từ quan điểm thiết kế, không có sự khác biệt giữa việc khai báo một thuộc tính và khai báo một cặp getter / setter (đó là thông lệ chung cho các giao diện).
MartinStettner

22
@ zooone9243, + MartinStettner: Đó là 6 tháng trước, tôi đã học được rất nhiều kể từ đó. Tôi sẽ lấy lại :)
Odys 21/03 '

47

Một sự khác biệt rất lớn thường bị bỏ qua và không được đề cập trong bất kỳ câu trả lời nào khác: ghi đè . Bạn có thể khai báo các thuộc tính ảo và ghi đè chúng trong khi bạn không thể làm tương tự cho các trường thành viên công cộng.


10

Đó là tất cả về phiên bản và tính ổn định API. Không có sự khác biệt, trong phiên bản 1 - nhưng sau đó, nếu bạn quyết định bạn cần biến nó thành một thuộc tính với một số loại kiểm tra lỗi trong phiên bản 2, bạn không phải thay đổi API của mình - không thay đổi mã, ở bất cứ đâu, ngoài định nghĩa của tài sản.


10

Một ưu điểm khác của các thuộc tính được triển khai tự động so với các trường công khai là bạn có thể đặt các bộ truy cập ở chế độ riêng tư hoặc được bảo vệ, cung cấp lớp đối tượng được xác định kiểm soát tốt hơn các trường công khai.


8

Không có gì sai trong việc làm một lĩnh vực public. Nhưng hãy nhớ tạo getter/settervới privatecác trường là không đóng gói. IMO, Nếu bạn không quan tâm đến các tính năng khác của a Property, bạn cũng có thể làm cho nó public.


1

Nếu sau đó bạn quyết định kiểm tra xem tiêu đề có phải là duy nhất hay không, bằng cách so sánh với bộ sưu tập hoặc cơ sở dữ liệu, bạn có thể làm điều đó trong thuộc tính mà không thay đổi bất kỳ mã nào phụ thuộc vào nó.

Nếu bạn đi chỉ với một thuộc tính công cộng thì bạn sẽ có ít linh hoạt hơn.

Tính linh hoạt bổ sung mà không phá vỡ hợp đồng là điều quan trọng nhất đối với tôi khi sử dụng các thuộc tính và cho đến khi tôi thực sự cần sự linh hoạt, việc tạo tự động có ý nghĩa nhất.


0

Một điều tôi thấy rất hữu ích cũng như tất cả các mã và lý do kiểm tra là nếu đó là một thuộc tính so với một trường là Visual Studio IDE hiển thị cho bạn các tham chiếu cho một thuộc tính chứ không phải là một trường.


0

POV của tôi sau khi làm một số nghiên cứu

  1. Thẩm định.
  2. Cho phép ghi đè người truy cập để thay đổi hành vi của một tài sản.
  3. Mục đích gỡ lỗi. Chúng ta sẽ có thể biết khi nào và những gì tài sản thay đổi bằng cách đặt một điểm dừng trong bộ truy cập.
  4. Chúng ta có thể có một trường chỉ thiết lập. Chẳng hạn, tập công khai () và private get (). Điều này là không thể với lĩnh vực công cộng.

Nó thực sự mang lại cho chúng ta nhiều khả năng và khả năng mở rộng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.