Thuộc tính tự động C # 3.0 - hữu ích hay không? [đóng cửa]


155

Lưu ý: Điều này đã được đăng khi tôi bắt đầu C #. Với kiến ​​thức năm 2014, tôi thực sự có thể nói rằng các thuộc tính tự động là một trong những điều tốt nhất từng xảy ra với ngôn ngữ C #.

Tôi được sử dụng để tạo các thuộc tính của mình trong C # bằng cách sử dụng trường riêng và trường công khai:

private string title;
public string Title
{
    get { return title;  }
    set { title = value;  }
}

Bây giờ, với .NET 3.0, chúng tôi đã có các thuộc tính tự động:

public string Title { get; set; }

Tôi biết đây không chỉ là một câu hỏi triết học / chủ quan, nhưng có lý do nào để sử dụng các thuộc tính tự động này ngoại trừ việc lưu năm dòng mã cho mỗi lĩnh vực không? Nắm bắt cá nhân của tôi là những tài sản đó đang che giấu tôi, và tôi không phải là một fan hâm mộ lớn của ma thuật đen.

Trong thực tế, trường riêng tư ẩn thậm chí không hiển thị trong trình gỡ lỗi, điều này ổn với thực tế là các hàm get / set không làm gì cả. Nhưng khi tôi thực sự muốn thực hiện một số logic getter / setter, tôi phải sử dụng cặp riêng / công khai.

Tôi thấy lợi ích là tôi tiết kiệm được rất nhiều mã (một so với sáu dòng) mà không mất khả năng thay đổi logic getter / setter sau đó, nhưng sau đó tôi có thể làm điều đó bằng cách chỉ cần khai báo trường công khai "Tiêu đề chuỗi công khai" mà không cần sự cần thiết của {get; bộ; } khối, do đó thậm chí tiết kiệm nhiều mã hơn.

Vì vậy, tôi đang thiếu gì ở đây? Tại sao bất cứ ai thực sự muốn sử dụng tài sản tự động?


86
"Nắm bắt cá nhân của tôi là những tài sản đó đang che giấu tôi và tôi không phải là một fan hâm mộ lớn của ma thuật đen." Huh? Bạn có biết rằng trình biên dịch ẩn một tấn từ bạn mọi lúc, phải không? Trừ khi bạn đang viết lắp ráp (hoặc chính xác hơn, 1 và 0 thực tế cho mã của bạn), MỌI THỨ bạn viết đều ẩn những thứ đó khỏi bạn.
Charles Boyung

Câu trả lời:


118

Chúng tôi sử dụng chúng mọi lúc trong Stack Overflow.

Bạn cũng có thể quan tâm đến một cuộc thảo luận về Thuộc tính so với Biến công khai . IMHO thực sự là những gì đây là một phản ứng, và với mục đích đó, nó thật tuyệt.


62

Vâng, nó chỉ lưu mã. Nó dễ đọc hơn khi bạn có vô số chúng. Chúng nhanh hơn để viết và dễ bảo trì hơn. Tiết kiệm mã luôn là một mục tiêu tốt.

Bạn có thể đặt phạm vi khác nhau:

public string PropertyName { get; private set; }

Vì vậy, tài sản chỉ có thể được thay đổi trong lớp. Điều này không thực sự bất biến vì bạn vẫn có thể truy cập trình thiết lập riêng thông qua sự phản chiếu.

Kể từ C # 6, bạn cũng có thể tạo readonlycác thuộc tính thực - tức là các thuộc tính bất biến không thể thay đổi bên ngoài hàm tạo:

public string PropertyName { get; }

public MyClass() { this.PropertyName = "whatever"; }

Tại thời điểm biên dịch sẽ trở thành:

readonly string pName;
public string PropertyName { get { return this.pName; } }

public MyClass() { this.pName = "whatever"; }

Trong các lớp bất biến với rất nhiều thành viên, điều này giúp tiết kiệm rất nhiều mã thừa.


"Vì vậy, bạn không mất bất kỳ chức năng." Làm thế nào để bạn gỡ lỗi chúng?
wal

2
@wal - Có gì để gỡ lỗi? Từ quan điểm đó về cơ bản bạn đang xử lý các biến thành viên.
Keith

6
@wal - Bạn có thể đặt một điểm dừng trên chúng, giống như bạn có thể truy cập vào một biến thành viên, bạn không thể bước vào chúng. Nhưng vì sao bạn lại muốn có nó? Những gì thuộc tính tự động thực sự làm là cả tầm thường và tự động được tạo ra, nếu bạn gặp lỗi đó là một nơi mà chúng cực kỳ khó xảy ra.
Keith

3
chúng ta có thể cần phải mang cái này ra ngoài Keith. :)
wal

1
Nhưng ok, giả sử bạn có nhiều lệnh gọi setter đến myObj.Title ... bạn muốn xem giá trị thay đổi từ "văn bản" thành null, tức là điểm dừng có điều kiện. Làm thế nào để bạn đạt được điều đó? bạn thậm chí không thể thiết lập một điểm dừng trên setter
wal

45

Ba nhược điểm lớn của việc sử dụng các trường thay vì các thuộc tính là:

  1. Bạn không thể dữ liệu đến một trường trong khi bạn có thể đến một thuộc tính
  2. Nếu bạn bắt đầu sử dụng một trường, bạn không thể (dễ dàng) thay đổi chúng thành một tài sản
  3. Có một số thuộc tính mà bạn có thể thêm vào thuộc tính mà bạn không thể thêm vào trường

7
"Nếu bạn bắt đầu sử dụng một lĩnh vực, sau này bạn không thể (dễ dàng) thay đổi chúng thành một tài sản", xin lỗi nhưng tại sao?
Homam

6
@Homam Chủ yếu, bất kỳ mã tiêu dùng nào sử dụng sự phản chiếu trên các trường của bạn sẽ bị phá vỡ, vì họ sẽ phải chuyển từ sử dụng FieldInfo sang PropertyInfo.
WCWedin

8
@Homam Ngoài ra, việc thay đổi một trường thành một thuộc tính phá vỡ khả năng tương thích nhị phân, đòi hỏi tất cả người tiêu dùng của trường phải biên dịch lại.
Odrade

1
vấn đề biên dịch lại và phản xạ sang một bên, rất dễ dàng đóng gói các trường bằng Visual Studio: Ctrl-R + E sẽ cho phép bạn biến một trường thành một thuộc tính với các getters / setters thích hợp. (hoặc bấm chuột phải vào trường, hệ số lại, trường đóng gói).
JoeBrockhaus

Các trường @Hommam là giá trị (chúng là biến) và thuộc tính thì không. Những thứ có thể được biên dịch khi nó là một lĩnh vực có thể không phải là một tài sản.
Đánh dấu

29

Cá nhân tôi thích tài sản tự động. Có gì sai khi lưu các dòng mã? Nếu bạn muốn làm công cụ trong getters hoặc setters, không có vấn đề gì để chuyển đổi chúng thành các thuộc tính bình thường sau này.

Như bạn đã nói, bạn có thể sử dụng các trường và nếu bạn muốn thêm logic vào chúng sau này, bạn sẽ chuyển đổi chúng thành các thuộc tính. Nhưng điều này có thể gây ra vấn đề với bất kỳ việc sử dụng phản xạ (và có thể ở nơi khác?).

Ngoài ra, các thuộc tính cho phép bạn đặt các cấp truy cập khác nhau cho getter và setter mà bạn không thể làm với một trường.

Tôi đoán nó giống như từ khóa var. Một vấn đề sở thích cá nhân.


29

Từ Bjarne Stroustrup, người tạo ra C ++:

Tôi đặc biệt không thích các lớp có nhiều hàm get và set. Đó thường là một dấu hiệu cho thấy nó không nên là một lớp học ở nơi đầu tiên. Nó chỉ là một cấu trúc dữ liệu. Và nếu nó thực sự là một cấu trúc dữ liệu, hãy biến nó thành một cấu trúc dữ liệu.

Và bạn biết những gì? Anh ấy đúng. Tần suất bạn chỉ đơn giản là bao bọc các trường riêng trong một get và set, mà không thực sự làm bất cứ điều gì trong get / set, đơn giản vì đó là việc "hướng đối tượng" để làm. Đây là giải pháp của Microsoft cho vấn đề này; về cơ bản chúng là các lĩnh vực công cộng mà bạn có thể liên kết.


2
Tôi thực sự nghĩ rằng điều này nên có nhiều điểm hơn. Có quá nhiều người coi các thuộc tính tự động là đèn xanh để viết các lớp được đóng gói khủng khiếp (hoặc không được gói gọn trong tất cả), ít hơn một lĩnh vực công cộng được tôn vinh. Tất nhiên đây là vấn đề liên quan đến cách mọi người sử dụng công cụ hơn là với chính công cụ đó, nhưng tôi nghĩ điều quan trọng cần đề cập khi thảo luận về các đặc tính nói chung.
sara

18

Một điều dường như không ai đề cập đến là làm thế nào các thuộc tính tự động không may không hữu ích cho các đối tượng bất biến (thường là các cấu trúc bất biến). Bởi vì điều đó bạn thực sự nên làm:

private readonly string title;
public string Title
{
    get { return this.title; }
}

(trong đó trường được khởi tạo trong hàm tạo thông qua tham số đã truyền và sau đó chỉ được đọc.)

Vì vậy, điều này có lợi thế hơn một đơn giản get/ private setautoproperty.


Nếu bạn có một cấu trúc thay đổi bất kỳ thuộc tính nào trên đó sẽ dẫn đến một cấu trúc mới. Đây chỉ là một vấn đề nếu bạn muốn một loại tham chiếu bất biến nội bộ - tôi không thể thấy lý do tại sao bạn cần một loại tham chiếu.
Keith

@Keith: Câu đầu tiên của bạn có vẻ không chính xác.
Domenic

3
Sẽ không public string Title { get; private set; }loại kết quả trong cùng một điều? Dĩ nhiên, bạn sẽ có thể thay đổi nó từ bên trong lớp, nhưng nếu bạn làm điều đó, bạn sẽ gặp vấn đề khác ...: p
Svish

2
@Svish - theo lập luận đó, không bao giờ nên sử dụng từ khóa chỉ đọc trong C # vì việc sử dụng nó có nghĩa là chúng tôi đang che giấu những "vấn đề khác nhau"
Zaid Masud

2
Tôi chỉ có nghĩa là từ một chế độ xem API bên ngoài, nó sẽ không tạo ra nhiều khác biệt. Và do đó, các thuộc tính tự động có thể được sử dụng nếu muốn. Điều tốt nhất tất nhiên sẽ là nếu bạn có thể làm điều gì đó nhưpublic string Title { get; private readonly set; }
Svish

12

Tôi luôn tạo các thuộc tính thay vì các trường công khai vì bạn có thể sử dụng các thuộc tính trong định nghĩa giao diện, bạn không thể sử dụng các trường công khai trong định nghĩa giao diện.


8

Thuộc tính tự động là một phép màu đen nhiều như mọi thứ khác trong C #. Khi bạn nghĩ về điều đó trong việc biên dịch xuống IL thay vì được mở rộng thành thuộc tính C # bình thường, trước tiên, nó sẽ ít ma thuật đen hơn rất nhiều so với các cấu trúc ngôn ngữ khác.


5

Tôi sử dụng các thuộc tính tự động tất cả các thời gian. Trước C # 3, tôi không thể bị làm phiền với tất cả các kiểu gõ và chỉ sử dụng các biến công khai.

Điều duy nhất tôi nhớ là có thể làm điều này:

public string Name = "DefaultName";

Bạn phải chuyển các mặc định thành các hàm tạo của bạn với các thuộc tính. tẻ nhạt :-(


4
Với công cụ khởi tạo thuộc tính Tự động từ C # 6, bạn sẽ sớm có thể thực hiện việc này: public string Name { get; set; } = "DefaultName"; blog.msdn.com/b/csharpfaq/archive/2014/11/20/ Lỗi
Carlos Muñoz

5

Tôi nghĩ rằng bất kỳ cấu trúc nào trực quan VÀ làm giảm các dòng mã là một điểm cộng lớn.

Những loại tính năng này là những gì làm cho các ngôn ngữ như Ruby trở nên mạnh mẽ (đó là các tính năng động, cũng giúp giảm mã thừa).

Ruby đã có tất cả những điều này như:

attr_accessor :my_property
attr_reader :my_getter
attr_writer :my_setter

2

Vấn đề duy nhất tôi có với họ là họ không đi đủ xa. Bản phát hành tương tự của trình biên dịch có thêm thuộc tính tự động, thêm phương thức một phần. Tại sao họ không đặt hai người lại gần nhau. Một "Thay đổi một phần <Tên tài sản> thay đổi" đơn giản sẽ làm cho những điều này thực sự hữu ích.


Bạn có thể đặt nhiều phương thức một phần bên trong phương thức khác. Tạo một mô hình tự động của một số loại cho họ sẽ gây nhầm lẫn.
Matthew Whited

2

Thật đơn giản, nó ngắn và nếu bạn muốn tạo ra một triển khai thực sự bên trong cơ thể của tài sản ở đâu đó bên dưới dòng, nó sẽ không phá vỡ giao diện bên ngoài của loại của bạn.

Đơn giản vậy thôi.


1

Một điều cần lưu ý ở đây là, theo hiểu biết của tôi, đây chỉ là đường cú pháp ở đầu C # 3.0, có nghĩa là IL được tạo bởi trình biên dịch là như nhau. Tôi đồng ý về việc tránh ma thuật đen, nhưng tất cả đều giống nhau, ít dòng hơn cho cùng một thứ thường là một điều tốt.


1

Theo tôi, bạn nên luôn luôn sử dụng các thuộc tính tự động thay vì các trường công khai. Điều đó nói rằng, đây là một sự thỏa hiệp:

Bắt đầu với một trường nội bộ bằng cách sử dụng quy ước đặt tên mà bạn sử dụng cho một thuộc tính. Khi bạn lần đầu tiên

  • cần truy cập vào các lĩnh vực từ bên ngoài lắp ráp của nó, hoặc
  • cần phải gắn logic với getter / setter

Làm cái này:

  1. đổi tên lĩnh vực
  2. làm cho nó riêng tư
  3. thêm một tài sản công cộng

Mã khách hàng của bạn sẽ không cần phải thay đổi.

Tuy nhiên, một ngày nào đó, hệ thống của bạn sẽ phát triển và bạn sẽ phân tách nó thành các cụm riêng biệt và nhiều giải pháp. Khi điều đó xảy ra, bất kỳ trường tiếp xúc nào sẽ quay trở lại ám ảnh bạn bởi vì, như Jeff đã đề cập, thay đổi trường công khai thành tài sản công cộng là một thay đổi API phá vỡ .


0

Tôi sử dụng CodeRush, nó nhanh hơn các thuộc tính tự động.

Để làm điều này:

 private string title;
public string Title
{
    get { return title;  }
    set { title = value;  }
}

Yêu cầu tám tổ hợp phím.


5
Nếu tôi giữ CTRL và V, tôi có thể dán rất nhiều thứ, / thực sự nhanh chóng /, nhưng điều đó không làm cho nó 'tốt hơn'. Làm thế nào để trả lời câu hỏi ban đầu?
JBRWilkinson

0

Vâng, với đoạn mã, một thuộc tính tự động cùng tên sẽ có tổng cộng bảy tổ hợp phím;)


0

@Domenic: Tôi không hiểu nó .. bạn không thể làm điều này với các thuộc tính tự động?:

public string Title { get; }

hoặc là

public string Title { get; private set; }

Đây có phải là những gì bạn đang đề cập đến?


Bạn có thể (cái sau; cái trước sẽ không biên dịch), nhưng sau đó trường không bất biến bên trong đối tượng của bạn.
Domenic

Lời cảnh báo, chỉ các cấu trúc là bất biến khi được gắn cờ chỉ đọc, các lớp chỉ là không thể gán được.
Guvante

0

Nắm bắt lớn nhất của tôi với các thuộc tính tự động là chúng được thiết kế để tiết kiệm thời gian nhưng tôi thường thấy tôi phải mở rộng chúng thành các thuộc tính đầy đủ sau này.

Cái mà VS2008 đang thiếu là một Tài sản tự động Explode tái cấu trúc .

Thực tế là chúng ta có một bộ tái cấu trúc trường đóng gói làm cho cách tôi làm việc nhanh hơn để chỉ sử dụng các trường công khai.

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.