2009-06-19 17 views
17

Tôi hiểu được nhiều lợi ích của việc cung cấp một giao diện để truy cập các thành viên của một lớp gián tiếp. Câu hỏi của tôi là: mà không phải là một cái gì đó đã bạn có thể thực tại chỉ là về bất kỳ ngôn ngữ OO sử dụng (một cái gì đó dọc theo dòng)Tại sao chúng ta sử dụng các thuộc tính .NET thay cho các hàm get/set cũ?

public int NormalClass::getQuality() { 
    return this->quality; 
} 

protected void NormalClass::setQuality(int q) { 
    this->quality = q; 
} 

?

Những lợi ích bổ sung nào mà thuộc tính .NET cung cấp, ngoài tính thẩm mỹ tuyệt đối?

Tôi sẽ chấp nhận "khả năng đọc" nếu bạn có thể đưa ra một đối số hấp dẫn cho nó; nhưng cá nhân, tôi nghiêng để nghĩ rằng một get/set chức năng là dễ đọc hơn một tài sản vì nó là rõ ràng một chức năng như trái ngược với một giá trị thẳng lên.

EDIT: Cảm ơn mọi người đã trả lời! Điều này thực sự mang tính thông tin cho tôi; để tổng hợp những gì tôi đã thu thập/học được từ tất cả những gì đã nói, sau đây là một vài kết luận tôi đã đạt đến cho đến nay:

  • Những lợi ích lớn nhất của tính đến không phải từ các tính năng cụ thể của tính bản thân, nhưng thay vào đó là từ các tính năng của khung công tác và tính năng IDE mà xử lý các thuộc tính theo cách đặc biệt; ví dụ: trình chỉnh sửa Thuộc tính, chuỗi tuần tự hóa XML , ràng buộc dữ liệu.
  • Thuộc tính có thể được điều trị giá trị như đơn giản trong một số cách thuận tiện rằng có được chức năng/bộ không thể: trong Đặc biệt, obj.Prop ++ và obj.Prop = giá trị.
  • Các thuộc tính cho phép bạn lấy đi bằng mã nhanh chóng và bẩn bằng cách sử dụng thành viên công khai mà không phải thông qua các chức năng get/set sau này; nếu bạn cần phải thêm một số logic và/hoặc đặt thành viên công khai ở chế độ riêng tư, , bạn có thể chỉ cần giới thiệu thuộc tính và không có nguy cơ vi phạm bất kỳ mã cũ nào.

Bây giờ, có một điểm được thực hiện trong 2 hoặc 3 câu trả lời cho đến nay cá nhân tôi thấy hơi mơ hồ: các thuộc tính đó ngụ ý các hoạt động đọc/ghi rẻ tiền và do đó có thể được sử dụng theo cách giống như biến đơn giản. Vấn đề của tôi với điểm này là không có gì vốn có trong các thuộc tính thực sự thực thi điều này; nó chỉ đơn giản là cách chúng được giả sử là để sử dụng. Đối với tôi, điều này tương tự với vòng loại "shouldBePrivate" cho biết giá trị nên chỉ được truy cập trực tiếp bởi lớp của riêng nó, nhưng vẫn có thể truy cập được từ bên ngoài; hoặc một lực lượng cảnh sát tuần tra các đường phố để nhắc nhở chúng tôi rằng chúng tôi nên hành xử, nhưng không thực sự can thiệp khi chúng tôi bắt đầu phạm tội (nếu nó không được thực thi, nó thực sự làm gì cho chúng ta?).

Tôi sẽ bị ấn tượng hơn bởi thời điểm này nếu các thuộc tính có một số loại cơ chế tích hợp để đảm bảo tính giá rẻ đọc/ghi.

+0

... chỉ vì bạn có thể, hehe –

+2

"nếu thuộc tính có một số cơ chế tích hợp để đảm bảo đọc/ghi giá rẻ" - Điều đó giống như nói "nó sẽ tốt hơn nếu [GUI yêu thích của bạn khuôn khổ] có một số loại cơ chế tích hợp để đảm bảo rằng mọi người không viết giao diện người dùng xấu ". Than ôi, cơ chế duy nhất cho điều đó được gọi là "lập trình viên". (Hoặc nhà thiết kế, hoặc nghiên cứu khả năng sử dụng, hoặc bất cứ điều gì.) Trình biên dịch có thể giúp bạn ra ngoài, nhưng bạn phải chịu trách nhiệm về việc không viết mã xấu. –

+1

Joe, tôi nghĩ đó là điểm cơ bản của tôi: rằng việc sử dụng các thuộc tính cho mỗi lần KHÔNG THỂ đảm bảo việc đọc/ghi không tốn kém. Đây là trách nhiệm của lập trình viên. Tôi không tranh luận rằng đó là một ý tưởng tốt cho khuôn khổ để có một stanard, cách tiếp cận xác nhận cho việc thực hiện các thuộc tính truy cập nhanh; thay vào đó, tôi đang đặt câu hỏi cho những câu trả lời đã chỉ ra tính năng thực tế này của các thuộc tính như một lợi ích chức năng, như thể đó là một số tính năng đặc biệt mà các nhà phát triển .NET đã làm việc chăm chỉ để cung cấp. –

Trả lời

24

Jon Skeet có tổng quan tuyệt vời về blog bài viết C# của anh ấy về why properties matter. Trong đó, ông giải thích lý do tại sao các thuộc tính nên được sử dụng trên các trường công khai.

Còn về lý do để sử dụng tài sản thay vì phương thức getter/setter, tôi sẽ đề nghị những suy nghĩ sau đây:

  • Thuộc tính cung cấp một trình dọn dẹp, ngắn gọn hơn cú pháp đó là dễ hiểu và đọc.
  • Thuộc tính bật chuỗi biểu thức chuyển nhượng: A.x = B.y = C.z
  • Thuộc tính truyền đạt ngữ nghĩa truy cập dữ liệu rõ ràng và nhất quán - người tiêu dùng mong đợi không có tác dụng phụ.
  • Thuộc tính được nhận dạng bởi nhiều thư viện trong .NET cho các tác vụ như serialization XML, ràng buộc WPF, liên kết ASP.NET 2 chiều và hơn thế nữa.
  • Thuộc tính được nhận dạng bởi IDE và nhiều nhà thiết kế trực quan và có thể được hiển thị trong trình chỉnh sửa thuộc tính.
  • Thuộc tính bật hỗ trợ cho toán tử tăng (++) và giảm (-).
  • Thuộc tính có thể dễ dàng phân biệt với các phương pháp sử dụng sự phản chiếu và cho phép người tiêu dùng năng động trích xuất kiến ​​thức về dữ liệu do đối tượng tiếp xúc.
  • C# 3 hỗ trợ các thuộc tính tự động giúp loại bỏ mã bản mẫu.
+0

Tôi nghĩ đây là câu trả lời toàn diện nhất của tất cả chúng. Làm tốt. –

+4

Không chỉ ++ và -, mà còn các toán tử sửa đổi gán như + =, * =, | =, v.v. –

+5

Chà, ngay cả khi Jon Skeet không trả lời câu hỏi, Jon Skeet đang trả lời câu hỏi :) – Oorang

13

Thuộc tính (đặc tính tự động đặc biệt trong.net 3.5) ngắn gọn hơn so với setters/getters, và ít dòng mã == ít mã hơn để duy trì == ít lỗi hơn.

Tôi có thể nói khả năng đọc đầu tiên, nhưng bạn đã nói rằng sẽ không được tính cho bạn .. :)

+0

Tôi chỉ đọc lên trên các thuộc tính tự động: có, điểm cũng được thực hiện ở đó. Tuy nhiên, đối với các thuộc tính cũ (trước 3,5), chúng chính xác hơn như thế nào? Tôi yêu cầu tò mò, không phải là tranh luận: các thuộc tính .NET, như tôi đã quen thuộc với chúng, dường như yêu cầu cùng một số dòng mã như các hàm get/set. Nhưng bạn nói điều này làm cho tôi cho rằng tôi có thể thiếu một cái gì đó. –

+0

Bạn nói đúng về số lượng dòng, tôi thậm chí không nhận thấy .. Tôi đoán tôi đã sử dụng tính chất tự động quá lâu .. Câu trả lời của LBushkin ở trên là rất lớn. –

+0

Về mặt lý thuyết, bạn có thể đặt các phương thức get và set của mình trên các đầu khác nhau trên tệp. Thuộc tính sẽ không cho phép bạn làm điều này. Tôi đề cập đến điều này bởi vì tôi đã gặp vấn đề nhiều lần trong đó mã không được căn chỉnh hợp lý. –

2

đối với tôi, thật dễ dàng:

myprop = myvalue; 
console.writeline(myprop); 

không cần

mysetfunc(myvalue); 
console.writeline(mygetprop); 

dễ nhớ hơn 1 điều hơn 2

+0

dường như có lỗi đánh máy tại mygetprop. nó nên được mygetprop() – usr

+3

hãy nói rằng đó là mã speudo và không thực mã ;-) – Fredou

2

Tôi biết trong một số trường hợp, bạn có thể sử dụng thuộc tính làm "Cột" tên như trong tập hợp dữ liệu. Tôi nghĩ .NET thực hiện điều này thông qua nội tâm. Tôi không tin rằng điều này là có thể với các chức năng get/set.

7

Có tài sản không chỉ bằng ngôn ngữ mà còn trong clr nghĩa là mọi người trên .NET đều có thể dựa vào siêu dữ liệu của họ. Một tài sản có một ý nghĩa của việc có được mà không có tác dụng phụ và cả hai nhận được và thiết lập là một hoạt động nhanh. Nhiều công cụ sử dụng các giả định này: nhà thiết kế winforms, LINQ to SQL ...

Vì vậy, nó không chỉ thuận tiện mà còn về việc có thêm một siêu dữ liệu nữa.

Dưới đây là các giả định thông thường khác:

customer.Name = "a"; 
Assert.IsTrue(customer.Name == "a"); 

try { var ignored = customer.Name; } 
catch { Assert.Fail("Exceptions are not expected"); } 
10

Tôi tin XML serialization chỉ đọc/viết tài sản công cộng, vì vậy get và phương pháp thiết lập sẽ được bỏ qua.

Ngoài ra, nếu bạn có một danh sách chung của các đối tượng, bạn có thể gán nó cho một DataGridView.DataSource và bạn sẽ nhận được một cột cho mỗi thuộc tính của bạn. Đó có thể là những gì @LPalmer đang đề cập đến.

+0

Tôi không biết một trong những điều này. Tôi đã không thực sự thực hiện bất kỳ công việc với serialization (chưa), nhưng điểm thứ hai của bạn về thế hệ cột là một cái gì đó mà thực sự có thể đến trong thực sự tiện dụng cho tôi - cảm ơn! –

0

Ít nhất là DataBinding
Phát triển liên quan đến giao diện người dùng trở nên phức tạp hơn nếu không có nó.

4

Hai lợi thế lớn để tính:

  • Họ có thể được hiển thị và chỉnh sửa trong lưới tài sản. Không có thuộc tính, làm cách nào bạn biết phương thức nào để hiển thị trình chỉnh sửa?
  • Chúng cung cấp gợi ý rằng một cái gì đó rẻ để đọc và viết và việc đọc sách đó không gây ra tác dụng phụ. (Nó có thể vi phạm điều đó, tất nhiên, nhưng bằng cách làm một cái gì đó một tài sản, bạn tuyên bố rằng đó là ý định của bạn.) Vì vậy, trình gỡ rối có thể lấy gợi ý đó. Nếu bạn di chuột qua thuộc tính, trình gỡ lỗi sẽ hiển thị giá trị của nó trong chú giải công cụ. Nó sẽ không có ý nghĩa để làm điều tương tự cho bất kỳ phương pháp có thể; quá dễ dàng để vô tình làm điều gì đó với các tác dụng phụ.
+0

Tôi thích điểm đầu tiên của bạn. Về thứ hai của bạn: Tôi có thể thấy bạn đến từ đâu, nhưng đây không phải là tính năng thực sự của tài sản mà chỉ là một quy ước được khuyến khích? Sau khi tất cả, NET có thể cung cấp một "WellCodedFunction" xây dựng để khuyến khích các nhà phát triển để mã tốt, nhưng nó sẽ không thực sự thêm bất kỳ chức năng thực sự. –

+0

Chắc chắn, họ có thể đã tạo thuộc tính "[FastWithNoSideEffects]" để cho biết "an toàn để hiển thị kết quả trong trình gỡ lỗi", và sau đó chỉ chú ý đến nó trên các hàm không tham số với giá trị trả về không trống. Nhưng các thuộc tính có vẻ như là một giải pháp đơn giản hơn. –

4

Một trong những cách phổ biến để xem xét lập trình hướng đối tượng là mô hình hóa các lớp trong chương trình của chúng tôi về các khái niệm trong đầu của chúng tôi.

Các khái niệm trong đầu của chúng tôi dựa trên các đối tượng thực tế mà chúng ta cảm nhận được xung quanh chúng ta (cho dù chúng ta cảm nhận chúng hoặc chúng ta giao tiếp với những người đã nhận thức chúng).

Các đối tượng xung quanh chúng ta - đồ đạc, động vật, tàu con thoi, v.v ... - có các tính chất cụ thể và hành động theo những cách cụ thể.

Đó là nơi chúng tôi nhận được các thuộc tính và phương pháp. Trong C#, một thuộc tính có thể không được giảm xuống thành một trường nhận được hoặc field-set (ví dụ, nó có thể yêu cầu kiểm tra bổ sung hoặc có thể có bộ nhớ đệm liên quan hoặc bất kỳ số lý do nào). Vì vậy, chúng ta cần một khái niệm riêng về các thuộc tính với các phương thức get và các phương thức set để làm cho các chương trình của chúng ta gần gũi hơn với các khái niệm mà chúng ta muốn chúng lập mô hình.

+0

Về khả năng yêu cầu kiểm tra bổ sung, bộ nhớ đệm, v.v. vâng, nhưng điều này không phân biệt một thuộc tính từ một cặp phương thức get/set, phải không? Về mặt khái niệm, tôi ở bên bạn. Nhưng tôi cũng nghĩ rằng nếu đây là mục đích duy nhất của các thuộc tính .NET, thì chúng sẽ không bổ sung nhiều vào các công cụ có sẵn. Nếu tôi có một hàm Box.getWidth(), tôi vẫn đang lập mô hình một đối tượng và cung cấp một cách để truy cập một trong các đặc tính của nó giống như thể tôi sử dụng thuộc tính Box.Width. Tất nhiên, các thuộc tính cũng có các tính năng hữu ích khác vì các câu trả lời khác đã rõ ràng. –

+1

Có, getWidth/setWidth có thể mô hình hóa ý tưởng của một thuộc tính trên một đối tượng. Nhưng họ không làm điều đó cũng như một cú pháp dành riêng cho các thuộc tính. Điểm lập trình là giúp chúng tôi chuyển kiến ​​thức của mình sang máy tính, vì vậy chúng tôi thiết kế các ngôn ngữ tương thích với cách suy nghĩ của mình. Theo cách suy nghĩ của chúng ta, các vật thể trong thế giới thực có đặc tính, không phải là getters và setters. Ý tưởng này, mà chúng tôi nghĩ về các đối tượng có đặc tính cụ thể và hành động theo những cách cụ thể, nhấn mạnh nhiều câu trả lời khác cho câu hỏi của bạn. – yfeldblum

2

Có thể là một điểm nhỏ, nhưng với getters/setters tôi thấy khó chịu khi tôi đi xe đạp qua chúng trong một IDE với 'intellisense' có một khối lớn 'getters' cạnh nhau và khối khác ' setters '. Tôi thấy khó tìm thấy những gì tôi đang tìm kiếm.

3

Thuộc tính tại bản chất nhận/đặt cặp phương thức.

Thuộc tính là phương pháp được hỗ trợ thời gian chạy để hiển thị cặp phương thức nhận được hỗ trợ siêu dữ liệu có nghĩa là chúng có thể phát hiện được bằng cách sử dụng phản chiếu mà không đoán phương pháp nào được tạo thành accessor dựa trên tên phương thức và chữ ký.

Ưu điểm khác của thuộc tính là chúng hoạt động giống như các trường cú pháp, và không giống như các phương thức, có lợi thế là tạo mã sạch hơn.

tôi nghiêng để nghĩ rằng một get/set chức năng là dễ đọc hơn so một tài sản vì nó là rõ ràng một hàm như trái ngược với một giá trị thẳng lên .

Hầu hết các thuộc tính thời gian được công cụ Jit sắp xếp, vì chúng rất đơn giản, có nghĩa là hầu hết các thuộc tính thời gian hoạt động giống như các trường hoạt động giống như chức năng. chức năng.

Trong trường hợp các thuộc tính, nó không quan trọng nếu có sự mơ hồ giữa cuộc gọi hàm và truy nhập trường vì phần lớn nhất bạn không trả chi phí gọi hàm, getters và setters thuộc tính, vì tính đơn giản của chúng, là ứng cử viên cao cho nội tuyến, có nghĩa là chi phí khôn ngoan là gần gũi hơn với các lĩnh vực hơn so với các cuộc gọi chức năng *.

  • Lưu ý: không phải tất cả các thuộc tính đều rẻ, nhưng nguyên tắc chung cho biết chúng phải đơn giản và nhẹ nhất có thể.
1

Như usr trạng thái:

"Một tài sản có một ý nghĩa của lấy được mà không có tác dụng phụ và cả get và set là một hoạt động nhanh chóng."

Chính xác. Nó được ngụ ý rằng một getter/setter sẽ nhanh chóng. Bằng cách phơi bày một cái gì đó như là tài sản bạn ngụ ý rằng bạn đang nhanh chóng lấy/đặt một thuộc tính trên một đối tượng. Phương pháp là để làm một số hình thức công việc giả định để tham gia nhiều chu kỳ hơn chỉ đơn giản là nhận/thiết lập một thuộc tính. Chúng ta thường đặt một thuộc tính 'hoạt động' dài vào một phương thức GetFoo (...)/SetFoo (...) để chỉ ra rằng hoạt động tính toán nặng hơn một thuộc tính.

0

Chúng cho phép người dùng loại có cú pháp đơn giản và cho phép bạn tạo trường chỉ đọc và chỉ ghi. Do đó me.SetAge (34); age = me.GetAge(); trở thành me.age = 34; age = me.age;

3

Bên cạnh tính chính xác ngữ nghĩa của việc sử dụng các thuộc tính cho một giá trị mà mô tả một tài sản của một đối tượng, bạn không thể tranh cãi với điều này:

obj.SetValue(obj.GetValue() + 1); 

vs

obj.Value++; 
2

Với getset phương pháp bạn phải quyết định sử dụng chúng ngay từ đầu và hầu như luôn viết nhiều mã soạn sẵn cho mọi thuộc tính công khai mà lớp học của bạn trưng ra.

class Point 
{ 
    private int x, y; 

    // Ew, pointless boilerplate! 
    public int getX()  { return x; } 
    public void setX(int x) { this.x = x; } 

    public int getY()  { return y; } 
    public void setY(int y) { this.y = y; } 
} 

// ... 

Point p = new Point(); 
p.setX(5); 
p.setY(10); 

Với thuộc tính bạn có thể loại bỏ những soạn sẵn getter và setter cho 90% tài sản có thu khí chỉ tầm thường và setters. Bạn chỉ có thể có các biến nào tiếp xúc trực tiếp

class Point 
{ 
    public int x, y; 
} 

Point p = new Point(); 
p.x = 5; 
p.y = 10; 

Sau đó, sau này nếu bạn quyết định bạn muốn thêm một số hành vi để biến công cộng của bạn, bạn có thể chuyển chúng đến các thuộc tính với hành vi thực tế trong get hoặc set phương pháp. Phía trên ở đây là người dùng lớp học của bạn không bị ảnh hưởng gì cả. Không có gì thay đổi; họ không phải chuyển từ point.x = 5 sang point.setX(5). Giao diện công khai của bạn ổn định, cho phép bạn sử dụng biến đồng bằng lúc đầu và chuyển sang chậm hơn get/set các phương pháp sau này khi bạn thêm một số bảo vệ/ghi nhật ký/bất kỳ thứ gì.

class Point 
{ 
    public int x { get; set; } 
} 

// No change! 
Point p = new Point(); 
p.x = 5; 
p.y = 10; 

(Bây giờ nói đúng, giao diện cú pháp của bạn vẫn không thay đổi, nhưng giao diện biên soạn của lớp học của bạn đã thay đổi, do đó bạn không phải biên dịch lại tất cả các mã có sử dụng lớp học của bạn nếu bạn chuyển từ biến để tính. Bạn không thể lấy đi chỉ với việc biên dịch lại lớp của bạn và thả nó vào vị trí của lớp cũ, nếu lớp của bạn là một phần của một thư viện được sử dụng rộng rãi, người dùng thư viện của bạn sẽ phải biên dịch lại mã của họ dựa vào phiên bản mới của thư viện của bạn. .)

+0

Tôi thích câu trả lời này rất nhiều, đặc biệt vì gần đây một đồng nghiệp của tôi gặp phải vấn đề này (cần phải thêm một số logic để thu hồi một số thành viên công khai), và vì vậy ông đã chuyển đổi các biến vấn đề thành FUNCTIONS. của các phần "có được" - tương đương với mã, trong khi phá vỡ một số địa điểm mà chúng tôi đã thực sự gán các giá trị. Nó đã được kết thúc dễ dàng để đi qua và sửa chữa; nhưng trong tầm nhìn, một tài sản sẽ là con đường để đi. Tôi cũng muốn nói thêm rằng tôi rất ấn tượng câu trả lời hùng biện này được viết bởi một con khỉ. –

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