2010-02-17 69 views
16

Có những tình huống mà tôi khai báo biến thành viên ở đầu lớp và sau đó khai báo thuộc tính để truy cập hoặc thiết lập biến thành viên đó, nhưng tôi tự hỏi liệu thuộc tính có cần thiết không nếu nó chỉ được truy cập và thiết lập từ bên trong lớp và không có nơi nào khác, vậy lợi thế của việc sử dụng một thuộc tính để truy cập và thiết lập biến thành viên thay vì chỉ làm trực tiếp đến biến thành viên là gì. Dưới đây là ví dụ:Sự khác biệt giữa biến thành viên và thuộc tính thành viên?

public class Car 
{ 

    int speed; //Is this sufficient enough if Car will only set and get it. 

    public Car(int initialSpeed) 
    { 
     speed = initialSpeed; 
    } 

    //Is this actually necessary, is it only for setting and getting the member 
     //variable or does it add some benefit to it, such as caching and if so, 
     //how does caching work with properties. 
    public int Speed 
    { 
     get{return speed;} 
     set{speed = value;} 
    } 

     //Which is better? 
     public void MultiplySpeed(int multiply) 
     { 
      speed = speed * multiply; //Line 1 
      this.Speed = this.Speed * multiply; //Line 2 

      //Change speed value many times 
      speed = speed + speed + speed; 
      speed = speed * speed; 
      speed = speed/3; 
      speed = speed - 4; 

     } 
} 

Ở trên, nếu tôi không có thuộc tính Tốc độ đặt và nhận tốc độ biến, và tôi quyết định thay đổi tốc độ thành int, tôi sẽ phải thay đổi tốc độ Tuy nhiên, nếu tôi sử dụng một thuộc tính như Speed ​​để thiết lập và nhận tốc độ, tôi sẽ chỉ phải thay đổi tốc độ thành spd trong việc nhận và thiết lập thuộc tính, vì vậy trong phương thức MutilplySpeed ​​của tôi, các công cụ như trên this.Speed ​​= this.Speed ​​+ this.Speed ​​+ this.Speed ​​sẽ không bị ngắt.

+0

có thể trùng lặp của [Sự khác nhau giữa một trường và thuộc tính trong C#?] (Http: // stackoverflow là gì.com/questions/295104/what-is-the-different-giữa-a-field-và-a-property-in-c) – nawfal

Trả lời

22

Nếu biến là private, tôi thường không tạo thuộc tính cho nó.Nếu đó là, trong bất kỳ cách nào, tiếp xúc với bên ngoài các loại, tôi luôn luôn tiếp xúc với nó thông qua một tài sản vì những lý do khác nhau:

  • Nó có thể không cần thiết ngày hôm nay, nhưng nếu nó trở nên cần thiết sau đó là một thay đổi phá vỡ
  • databinding chỉ hoạt động trên tài sản, chứ không phải trên các lĩnh vực (tôi nghĩ, không phải là một người sử dụng liên kết dữ liệu lớn)
  • Nó cho phép để chèn kiểm chứng thực, khai thác gỗ, breakpoint khi truy cập vào giá trị

Ngoài ra, nếu lĩnh vực này được tiếp xúc thông qua một tài sản, tôi luôn truy cập thông qua tài sản, ngay cả trong e lớp.

Cập nhật
Để phản hồi các mẫu mã được cập nhật của bạn: có một số điều cần xem xét xung quanh thiết kế mã tại đây.

  • Độ khó vs Speed ​​
  • "Atomicity"
  • tác dụng phụ khác

Một mảnh đặc trưng của tư vấn (mà tôi tìm thấy rất tốt) là "viết cho rõ ràng, kiểm tra để thực hiện" . Điều đó có nghĩa là khi bạn viết mã của mình, mối quan tâm đầu tiên của bạn phải là liệu mã có rõ ràng khi xem nó không. Điều này thường (nhưng không phải luôn luôn) quan trọng hơn tốc độ thô của mã. Viết tối ưu hóa tốc độ khi bạn đã thiết lập nơi bạn đạt được nó. Việc truy cập tài sản sẽ chậm hơn một chút so với việc đọc trực tiếp trường, nhưng trong hầu hết các trường hợp, sự khác biệt sẽ không đáng kể (nếu có thể đo lường được).

Nguyên tử có thể là sự cố. Với mẫu mã của bạn, chúng tôi có trường speed, được hiển thị công khai qua thuộc tính Speed. Nếu phương pháp MultiplySpeed cần thực hiện một số cập nhật cho giá trị, các giá trị trung gian đó sẽ có sẵn thông qua thuộc tính Speed vào các thời điểm khác nhau trong khi tính toán đang diễn ra. Điều này đúng bất kể bạn cập nhật trường trực tiếp hay thông qua thuộc tính. Trong trường hợp như thế này có lẽ tốt hơn là trước hết nên đặt giá trị vào biến cục bộ, sử dụng giá trị đó cho phép tính và gán giá trị của biến đó trở lại thuộc tính khi hoàn thành.

Cuối cùng, các tác dụng phụ khác. Có thể thay đổi giá trị của Speed sẽ tăng một sự kiện (chẳng hạn như SpeedChanged). Trong trường hợp như vậy, nó cũng có thể là một ý tưởng tốt không để thực hiện cập nhật cho đến khi tính toán được thực hiện.

Tôi muốn nghĩ về thuộc tính là hợp đồng và trường là triển khai. Bất kỳ ai (trừ lõi của loại của tôi) cần giá trị nên sử dụng hợp đồng. Dựa vào việc thực hiện chỉ nên thực hiện nếu có lý do chính đáng để bỏ qua hợp đồng.

Và có, nếu bạn đóng gói quyền truy cập vào trường trong thuộc tính, việc thay đổi tên của trường sẽ thay đổi ít hơn (và có lẽ tên của trường trở nên ít quan trọng hơn).

Tôi hy vọng điều đó có ý nghĩa và không quá nhiều chủ đề;)

+0

Các thuộc tính cũng có thể truy cập/cài đặt được qua phản ánh –

+0

Tôi đồng ý với việc sử dụng thuộc tính ngay cả trong lớp, ngay cả trong hàm tạo. Thật tuyệt khi biết logic xác thực của bạn là * luôn luôn * được gọi. –

+0

+1 để sử dụng một trường thông qua một thuộc tính ngay cả từ bên trong, vì nó tránh được các lỗi "setter-doesnt-run-when-it-should" khó chịu. – OregonGhost

0

Một điều bạn quên đề cập đến, các thuộc tính sẽ giúp bạn khi bạn mở rộng lớp học. Nếu lớp học của bạn được thiết kế đúng, các biến của bạn bên trong lớp cơ sở phải là private. Không có các thuộc tính thực tế public thuộc tính. Bạn sẽ không có cách nào để truy cập các biến riêng tư này từ bên trong lớp mở rộng của bạn. Chúng tôi đang nói chuyện công cộng vs riêng tư và tôi không bao gồm bảo vệ vì một lý do :).

Chỉ cần một số lưu ý đáng nói:

  • tính cụ hỗ trợ khi một lớp được mở rộng
  • tính để tôi làm cho mã dễ đọc hơn một chút (trong this.privateVariable Ngoài verson PublicPropertyVariableName)
  • thuộc tính có thể đảm bảo chỉ đọc, bộ riêng, công khai được vv (dễ đọc hơn nhiều đối với các lập trình viên khác). Hãy xem xét một trường hợp một IDentifier cần một công chúng nhận được nhưng một tập hợp riêng
  • Cá nhân tôi quá nhiều tập hợp/dường như làm phức tạp mã, làm cho mã ít đọc được, quá nhiều cú pháp không cần thiết
  • thừa kế/mở rộng đến một lớp mở rộng không cho phép bạn kế thừa các biến riêng tư, các thuộc tính là câu trả lời. (một lần nữa không đề cập đến việc bảo vệ ở đây, đó là một câu chuyện khác)
  • Với tôi ngay cả khi lớp đó có biến riêng, các phương thức lớp của tôi vẫn sử dụng thuộc tính để truy cập hoặc sử dụng biến riêng đó
  • Đừng quên xác nhận, nó làm cho nó dễ dàng hơn nhiều để xác nhận đặc biệt là khả năng đọc khôn ngoan.

Đây chỉ là một số điều phổ biến (2 xu của tôi mặc dù trên hầu hết trong số chúng).

+0

Vì vậy, tôi lấy nó từ câu trả lời của bạn bằng cách đặt các biến riêng tư và sử dụng các thuộc tính để đặt và nhận được chúng, tôi đang tận dụng lợi thế của đóng gói? – Xaisoft

+0

Bạn cũng có thể thực hiện điều đó với các biến được bảo vệ. – cyberconte

1

Những thứ như xác thực có thể được bao phủ tại một nơi. Các thành viên được đóng gói, và bạn muốn phải lo lắng về xác nhận và những thứ khác từ phần còn lại của lớp học của bạn. Trong trường hợp hiện tại của bạn, nó không thực sự tạo sự khác biệt, nhưng khi bạn cần thay đổi biến hoặc cần thêm hành vi, sẽ dễ dàng hơn khi bạn sử dụng thuộc tính, vì bạn chỉ có một nơi bạn cần thay đổi nó .

1

nó không thêm bộ nhớ đệm nhưng nó cho phép một giao diện nhất quán.

hãy tưởng tượng bạn phải tăng tốc độ bằng cách thêm một hằng số vào nó trong tương lai. sử dụng biến thành viên sẽ khó khăn khi mà thuộc tính cho phép thao tác này.

Ngoài nội bộ trong lớp, bạn nên truy cập lại thuộc tính để nhất quán (hãy tưởng tượng kịch bản ở trên nơi bạn có một lớp truy cập trực tiếp biến thành viên).

1

Lý do chính đáng duy nhất tôi biết là nếu trường được truy cập từ bên ngoài hội đồng. Trong trường hợp đó, nếu bạn muốn thêm chức năng ánh sáng vào trường đó (có thể đặt cờ Bẩn hoặc xác thực thay đổi), bạn phải thay đổi nó thành thuộc tính thay đổi cách mà hội đồng gọi đang xem, cũng sẽ cần xây dựng lại . Trong trường hợp rất hiếm, bạn có thể thấy rằng bạn không có quyền kiểm soát hội đồng đó, sau đó bạn có một vấn đề.

Đừng để những người nhiệt tình của OO cho bạn biết rằng nó sai về mặt ngữ pháp khi sử dụng các trường công cộng, mặc dù tôi có thể đồng ý rằng các thuộc tính tự động làm cho đối số phần nào tranh luận.

+2

"Đừng để những người hâm mộ OO nói với bạn rằng nó sai về mặt ngữ pháp khi sử dụng các trường công cộng, mặc dù tôi có thể đồng ý rằng các thuộc tính tự động làm cho đối số phần nào tranh luận." Tôi không có nhiệt huyết OO nhưng đó là thực hành xấu. Tất cả các biến thành viên phải là riêng tư. – JonH

+0

Tôi đánh giá cao các quan điểm khác nhau. – Xaisoft

+0

Tại sao, JonH? Đừng hiểu lầm tôi, tôi đã từng nghĩ như vậy; Tôi vẫn làm điều đó nếu tôi thành thật. Nhưng bị thách thức để giải thích tại sao, tôi không có câu trả lời nào tốt hơn câu trả lời tôi vừa đưa ra. – pdr

8

Tôi đồng ý với câu trả lời Frederik's. Một điều làm cho nó ít làm việc hơn để làm theo lời khuyên của ông là sử dụng các thuộc tính tự động. Đó chỉ là những thuộc tính tự động tạo ra logic getter/setter tiêu chuẩn. Bạn không nhận được bất kỳ xác thực nào, nhưng bạn luôn có thể thay thế thuộc tính tự động bằng thuộc tính chuẩn sau này. Sự thay thế này không phải là một sự thay đổi đột ngột.

Ở đây tôi đã thay thế thuộc tính Tốc độ trong ví dụ của bạn bằng thuộc tính tự động. Lưu ý rằng biến thành viên biến mất và lớp học của bạn phải truy cập nó thông qua thuộc tính.

public class Car 
{ 
    public Car(int initialSpeed) 
    { 
     Speed = initialSpeed; 
    } 

    public int Speed { get; set; } 

    public void MultiplySpeed(int multiply) 
    { 
     Speed *= multiply; 
    } 
} 

Bạn cũng có thể sử dụng một hương vị khác gọi là "nhận với bộ riêng tư". Điều này có nghĩa rằng getter là công khai, nhưng setter là riêng tư. Bạn xác định nó như sau:

public int Speed { get; private set; } 

Đối với câu hỏi của bạn về tiền tố this., nó thường không liên quan. Thời gian duy nhất nó quan trọng là khi bạn đã xác định một tham số phương thức hoặc biến cục bộ có cùng tên như một biến thành viên. Sau đó, bạn có thể sử dụng this để truy cập vào biến thành viên.

+0

Cảm ơn ví dụ. – Xaisoft

1

Thực tế là, không có nhiều sự khác biệt giữa trường được khai báo công khai và thuộc tính công khai với một cửa hàng sao lưu riêng tư nếu không có thêm logic. Điều đó đang được nói, nó vẫn được coi là thực hành tốt nhất để sử dụng tài sản.

Và trước khi mọi người nhảy vào tôi về khả năng mở rộng, hãy nhớ rằng nếu sau này bạn cần thêm chức năng, bạn có thể giữ tên với thuộc tính và giới thiệu tên mới cho cửa hàng sao lưu để không thay đổi đột ngột.

0

Theo tôi, thiết kế ngôn ngữ bị hỏng. Không nên có hai cách để làm những thứ có quá nhiều sự chồng chéo ngữ nghĩa. Thuộc tính/Trường nên liên tục cung cấp các lợi ích của phương pháp tiếp cận tùy thuộc vào cách chúng được sử dụng. Nếu chương trình sử dụng tối thiểu các tính năng của Thuộc tính, chúng sẽ hoạt động giống như các trường. Không nên cần khai báo lấy sản phẩm nào; và thiết lập; phương pháp trong trường hợp này. Sự khác biệt tấn công tôi như nhân tạo.

Đó là một ngôn ngữ tuyệt vời; và khá sạch sẽ cho hầu hết các phần. Điều đó không có nghĩa là nó không nên được cải thiện khi "lần sau".

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