2009-03-17 25 views
127

Tôi nhận ra rằng nó có vẻ là một bản sao của What is the difference between a Field and a Property in C#? nhưng câu hỏi của tôi có một khác biệt nhỏ (từ quan điểm của tôi):Sự khác nhau giữa tài sản và Field trong C# 3.0+

Một khi tôi biết rằng

  • Tôi sẽ không sử dụng lớp học của mình bằng "các kỹ thuật chỉ hoạt động trên các thuộc tính" và
  • Tôi sẽ không sử dụng mã xác nhận trong trình lấy/lấy.

Có sự khác biệt nào (ngoại trừ kiểu phát triển/kiểu tương lai), giống như một số loại kiểm soát trong cài đặt thuộc tính?

Có sự khác biệt bổ sung giữa:

public string MyString { get; set; } 

public string myString; 

(Tôi biết rằng, đó là phiên bản đầu tiên đòi hỏi C# 3.0 hoặc cao hơn và rằng trình biên dịch không tạo ra các lĩnh vực cá nhân .)

+0

bản sao có thể có của [Getters và setters được triển khai tự động so với các trường công khai] (http://stackoverflow.com/questions/111461/auto-implemented-getters-and-setters-vs-public-fields) – nawfal

Trả lời

108

Đóng gói.

Trong trường hợp thứ hai bạn vừa xác định một biến, trong trường hợp đầu tiên, có một bộ thu thập thông tin/setter xung quanh biến. Vì vậy, nếu bạn quyết định bạn muốn xác thực biến vào một ngày sau đó - nó sẽ dễ dàng hơn nhiều.

Ngoài ra chúng hiển thị khác nhau trong Intellisense :)

Edit: Cập nhật cho Ops cập nhật câu hỏi - nếu bạn muốn bỏ qua những gợi ý khác ở đây, lý do khác là nó chỉ đơn giản là không thiết kế OO tốt. Và nếu bạn không có lý do chính đáng để thực hiện việc đó, hãy luôn luôn chọn thuộc tính trên một biến/trường công khai.

+8

Tại sao nó dễ hơn không? Điều gì ngăn cản tôi biến trường thành thuộc tính và thêm trường sao lưu riêng tư? Điều này ảnh hưởng đến mã gọi điện như thế nào? –

+27

@Serge - Nó ảnh hưởng đến mã đã được biên dịch. Ví dụ, nếu bạn đang phát triển một thư viện được nhiều ứng dụng sử dụng, việc thay đổi một trường thành một thuộc tính trong thư viện đó sẽ yêu cầu biên dịch lại từng ứng dụng. Nếu đó là tài sản, bạn có thể cập nhật thuộc tính mà không cần lo lắng. –

+0

Tôi hoàn toàn đồng ý với bạn, tôi luôn sử dụng tài sản. Tôi chỉ tò mò về một sự khác biệt có thể là – p4bl0

7

Thứ nhất:

public string MyString {get; set; } 

là một tài sản; cái thứ hai (public string MyString) biểu thị một trường.

Sự khác biệt là, một số kỹ thuật (ASP.NET databinding cho các trường hợp), chỉ hoạt động trên các thuộc tính và không hoạt động trên các trường. Điều tương tự cũng đúng đối với việc tuần tự hóa XML: chỉ các thuộc tính được tuần tự hóa, các trường không được tuần tự hóa.

+8

Sai. XML Serialization DOES serialize các trường công khai. –

+2

Có thể. Nhưng khi bạn tạo một nguồn dữ liệu đối tượng từ một lớp, bạn chỉ có thể sử dụng các thuộc tính chứ không phải các trường. (Trừ khi tôi đã làm một cái gì đó sai: P) – Svish

+0

Tốt là để DRY;) nhưng tôi viết một lần nữa, tôi thích vai trò mạnh mẽ của tài sản trong ngôn ngữ C#. Được thực hiện tốt hơn nhiều so với Java (do đó từ đầu) Nhiều, có lẽ tất cả các giải pháp .net chỉ hoạt động trên các thuộc tính. WPF, ASPX và nhiều hơn nữa. –

40

Một cặp vợ chồng nhanh chóng, sự khác biệt rõ ràng

  1. Một tài sản có thể có từ khóa accessor.

    public string MyString { get; private set; } 
    
  2. Thuộc tính có thể được ghi đè trong hậu duệ.

    public virtual string MyString { get; protected set; } 
    
+0

mmh .. nr 2 là thú vị .. tôi không nghĩ về nó – p4bl0

+1

thêm phiên bản cho rằng :) –

13

Sự khác biệt cơ bản là một lĩnh vực là một vị trí trong bộ nhớ nơi dữ liệu của các loại quy định được lưu trữ. Một thuộc tính thể hiện một hoặc hai đơn vị mã được thực hiện để truy lục hoặc thiết lập một giá trị của kiểu được chỉ định.Việc sử dụng các phương thức truy cập này được ẩn theo cú pháp bằng cách sử dụng một thành viên xuất hiện để hoạt động giống như một trường (ở chỗ nó có thể xuất hiện ở hai bên của một phép toán gán).

3

Thuộc tính và trường có thể, trong nhiều trường hợp, có vẻ tương tự, nhưng chúng không giống nhau. Có những hạn chế đối với các thuộc tính không tồn tại cho các trường và ngược lại.

Như những người khác đã đề cập. Bạn có thể tạo thuộc tính chỉ đọc hoặc chỉ ghi bằng cách đặt quyền truy cập riêng cho nó. Bạn không thể làm điều đó với một lĩnh vực. Thuộc tính cũng có thể là ảo, trong khi các trường không thể.

Hãy suy nghĩ về các thuộc tính làm đường cú pháp cho các hàm getXXX()/setXXX(). Đây là cách chúng được thực hiện phía sau hậu trường.

145

Các trường và thuộc tính trông giống nhau, nhưng chúng không giống nhau. Các thuộc tính là các phương thức và như vậy có những thứ nhất định không được hỗ trợ cho các thuộc tính và một số điều có thể xảy ra với các thuộc tính nhưng không bao giờ trong trường hợp của các trường.

Dưới đây là danh sách các sự khác biệt:

  • Fields có thể được sử dụng như là đầu vào cho out/ref đối số. Thuộc tính có thể không.
  • Trường sẽ luôn mang lại kết quả tương tự khi được gọi nhiều lần (nếu chúng tôi loại bỏ nhiều vấn đề với nhiều chuỗi). Một tài sản như DateTime.Now không phải lúc nào cũng bằng chính nó.
  • Thuộc tính có thể ném ngoại lệ - các trường sẽ không bao giờ làm điều đó.
  • Thuộc tính có thể có phản ứng phụ hoặc mất nhiều thời gian để thực thi. Các trường không có tác dụng phụ và sẽ luôn luôn nhanh như mong đợi đối với loại đã cho.
  • Thuộc tính hỗ trợ khả năng tiếp cận khác nhau đối với getters/setters - lĩnh vực không (nhưng lĩnh vực có thể được thực hiện readonly)
  • Khi sử dụng phản ánh các thuộc tính và các lĩnh vực được coi là khác nhau MemberTypes vì vậy họ đang nằm cách khác nhau (GetFields vs GetProperties ví dụ)
  • Trình biên dịch JIT có thể coi quyền truy cập thuộc tính rất khác so với truy cập trường. Tuy nhiên, nó có thể biên dịch xuống mã gốc giống hệt nhau nhưng phạm vi cho sự khác biệt là ở đó.
+11

Lưu ý tuy nhiên một số trong những điểm này nên * không * là khác biệt nếu thực hành tốt được sử dụng. Đó là, tài sản thực sự không bao giờ nên có tác dụng phụ, cũng không nên mất một thời gian dài để thực hiện. – Noldorin

+13

@Noldorin: Tôi đồng ý, nhưng rất tiếc * nên * là từ khóa ở đây. Với các lĩnh vực mà hành vi được đảm bảo. Tôi không nói bạn nên sử dụng các lĩnh vực, nhưng điều quan trọng là phải nhận thức được sự khác biệt ngữ nghĩa. –

+4

Vâng, đủ công bằng. Các lập trình viên mới bắt đầu không có đầu mối về những thứ này, thật không may ... – Noldorin

10

Trình truy cập nhiều hơn trường. Những người khác đã chỉ ra một số khác biệt quan trọng, và tôi sẽ thêm một số khác nữa.

Thuộc tính tham gia vào các lớp giao diện. Ví dụ:

interface IPerson 
{ 
    string FirstName { get; set; } 
    string LastName { get; set; } 
} 

Giao diện này có thể được thỏa mãn theo nhiều cách. Ví dụ:

class Person: IPerson 
{ 
    private string _name; 
    public string FirstName 
    { 
     get 
     { 
      return _name ?? string.Empty; 
     } 
     set 
     { 
      if (value == null) 
       throw new System.ArgumentNullException("value"); 
      _name = value; 
     } 
    } 
    ... 
} 

Thực hiện điều này, chúng tôi đang bảo vệ cả hai lớp Person từ đi vào một trạng thái không hợp lệ, cũng như người gọi từ nhận rỗng ra khỏi bất động sản không được gán.

Nhưng chúng tôi có thể đẩy thiết kế thêm nữa. Ví dụ, giao diện có thể không đối phó với setter.Đó là hoàn toàn hợp pháp để nói rằng người tiêu dùng của giao diện IPerson chỉ quan tâm đến nhận tài sản, không đặt nó:

interface IPerson 
{ 
    string FirstName { get; } 
    string LastName { get; } 
} 

thực hiện trước của Person đáp ứng lớp giao diện này. Thực tế là nó cho phép người gọi cũng thiết lập các thuộc tính là vô nghĩa từ quan điểm của người tiêu dùng (người tiêu thụ IPerson). chức năng bổ sung việc thực hiện cụ thể được đưa vào xem xét bằng cách, ví dụ, xây dựng:

class PersonBuilder: IPersonBuilder 
{ 
    IPerson BuildPerson(IContext context) 
    { 

     Person person = new Person(); 

     person.FirstName = context.GetFirstName(); 
     person.LastName = context.GetLastName(); 

     return person; 

    } 
} 

... 

void Consumer(IPersonBuilder builder, IContext context) 
{ 
    IPerson person = builder.BuildPerson(context); 
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName); 
} 

Trong mã này, người tiêu dùng không biết về setters tài sản - nó không phải là kinh doanh của mình để biết về nó. Người tiêu dùng chỉ cần getters, và anh ta nhận được getters từ giao diện, tức là từ hợp đồng.

Một thực hiện hoàn toàn hợp lệ IPerson sẽ là một lớp người bất biến và một nhà máy người tương ứng:

class Person: IPerson 
{ 
    public Person(string firstName, string lastName) 
    { 

     if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName)) 
      throw new System.ArgumentException(); 

     this.FirstName = firstName; 
     this.LastName = lastName; 

    } 

    public string FirstName { get; private set; } 

    public string LastName { get; private set; } 

} 

... 

class PersonFactory: IPersonFactory 
{ 
    public IPerson CreatePerson(string firstName, string lastName) 
    { 
     return new Person(firstName, lastName); 
    } 
} 
... 
void Consumer(IPersonFactory factory) 
{ 
    IPerson person = factory.CreatePerson("John", "Doe"); 
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName); 
} 

Trong mẫu tiêu dùng mã một lần nữa không có kiến ​​thức về làm đầy các thuộc tính. Người tiêu dùng chỉ thỏa thuận với getters và thực hiện cụ thể (và logic kinh doanh đằng sau nó, như kiểm tra nếu tên là trống) là trái để các lớp học chuyên ngành - nhà xây dựng và nhà máy. Tất cả các hoạt động này hoàn toàn không thể thực hiện được với các trường.

1

Có một khác biệt quan trọng khác giữa các trường và thuộc tính.

Khi sử dụng WPF, bạn chỉ có thể liên kết với các thuộc tính công khai. Liên kết với một trường công khai sẽ không hoạt động. Điều này đúng ngay cả khi không triển khai INotifyPropertyChanged (mặc dù bạn luôn luôn nên làm như vậy).

+0

Tốt là để DRY;) nhưng tôi viết một lần nữa, tôi thích vai trò mạnh mẽ của tài sản trong ngôn ngữ C#. Được thực hiện tốt hơn nhiều so với Java (do đó từ đầu) Nhiều, có lẽ tất cả các giải pháp .net chỉ hoạt động trên các thuộc tính. WPF, ASPX và nhiều hơn nữa. –

0

Bạn nên luôn sử dụng các thuộc tính thay vì trường cho bất kỳ trường công cộng nào. Điều này đảm bảo rằng thư viện của bạn có khả năng thực hiện đóng gói cho bất kỳ trường nào nếu được yêu cầu trong tương lai mà không vi phạm các mã hiện có. các thư viện hiện có thì tất cả các mô đun phụ thuộc sử dụng thư viện của bạn cũng cần phải được xây dựng lại.

+0

"luôn luôn" là một liitle từ khó. Trong C# (tốt hơn trong Java) tài sản có vị trí mạnh mẽ, là (có lẽ không có ngoại lệ) chính/phương pháp "ràng buộc" trong ASP, WPF và những người khác. Nhưng dù sao tôi có thể tưởng tượng thiết kế với cánh đồng không có tài sản có ý nghĩa (đôi khi) –

0

Trong số các câu trả lời và ví dụ khác, tôi nghĩ ví dụ này hữu ích trong một số trường hợp.

Ví dụ chúng ta hãy nói rằng bạn có một OnChangeproperty như sau:

public Action OnChange { get; set; } 

Nếu bạn muốn sử dụng các đại biểu hơn bạn cần phải thay đổi nó OnChange-field như thế này:

public event Action OnChange = delegate {}; 

Trong trường hợp đó, chúng tôi bảo vệ trường của mình khỏi bị truy cập hoặc sửa đổi không mong muốn.

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