Thuộc tính tự động chỉ có getter, có thể được thiết lập, tại sao?


95

Tôi đã tạo một thuộc tính tự động:

public int Foo { get; } 

Đây chỉ là getter. Nhưng khi tôi tạo một hàm tạo, tôi có thể thay đổi giá trị:

public MyClass(string name)
{
    Foo = 5;
}

Tại sao nó có thể, mặc dù điều này chỉ nhận được?


Nó không thực sự sử dụng setter (vì nó không có). Nó trực tiếp thiết lập trường cơ bản (được ẩn từ chúng tôi, đó là lý do tại sao bạn cần phải sử dụng tên tài sản)
Dennis_E

14
Thuộc tính có công dụng gì, nếu nó không bao giờ có thể được khởi tạo / thiết lập? Yacoub Massad đã trả lời nó một cách hoàn hảo
Vikhram

Câu trả lời:


122

Đây là một tính năng mới của C # 6, "Thuộc tính tự động chỉ dành cho người nhận", còn được gọi là "Bộ khởi tạo thuộc tính tự động cho thuộc tính chỉ đọc" như được thảo luận trong bài báo trên tạp chí MSDN này 'C #: C # 6.0' mới và cải tiến của Mark Michaelis và trong Đặc tả ngôn ngữ dự thảo C # 6.0 .

Bộ thiết lập của trường chỉ đọc chỉ có thể truy cập được trong phương thức khởi tạo, trong tất cả các trường hợp khác, trường vẫn chỉ được đọc và hoạt động như trước.

Đây là một cú pháp tiện lợi để giảm số lượng mã bạn cần nhập và loại bỏ nhu cầu khai báo rõ ràng một biến cấp mô-đun riêng để giữ giá trị.

Tính năng này được coi là quan trọng, kể từ khi giới thiệu Thuộc tính tự động triển khai trong C # 3, các thuộc tính có thể thay đổi (những thuộc tính có getter và setter) đã trở nên nhanh hơn để viết so với những bất biến (những thuộc tính chỉ có getter), có nghĩa là mọi người bị cám dỗ để sử dụng các thuộc tính có thể thay đổi để tránh phải nhập mã cho trường hỗ trợ thường được yêu cầu cho các thuộc tính chỉ đọc. Có thêm thảo luận về các thuộc tính Tự động triển khai trong phần liên quan của Hướng dẫn lập trình Microsoft C # .

Bài đăng trên blog này, '# 1.207 - C # 6.0 - Trình khởi tạo Thuộc tính Tự động cho Thuộc tính Chỉ Đọc' của Sean Sexton Có giải thích và ví dụ tốt như sau:

Trước C # 6.0, nếu bạn muốn một thuộc tính chỉ đọc (không thể thay đổi), bạn thường sử dụng trường hỗ trợ chỉ đọc được khởi tạo trong hàm tạo, như được hiển thị bên dưới.

public class Dog 
{
    public string Name { get; set; }

    // DogCreationTime is immutable
    private readonly DateTime creTime;
    public DateTime DogCreationTime 
    {
        get { return creTime; }
    }

    public Dog(string name)
    {
        Name = name;
        creTime = DateTime.Now;
    }
}

Trong C # 6.0, bạn có thể sử dụng các thuộc tính được triển khai tự động để triển khai thuộc tính chỉ đọc. Bạn thực hiện việc này bằng cách sử dụng trình khởi tạo thuộc tính tự động. Kết quả rõ ràng hơn nhiều so với ví dụ trên, trong đó chúng ta phải khai báo rõ ràng một trường hỗ trợ.

public class Dog
{
    public string Name { get; set; }

    // DogCreationTime is immutable
    public DateTime DogCreationTime { get; } = DateTime.Now;

    public Dog(string name)
    {
        Name = name;
    }
}

Bạn cũng có thể tìm thấy thêm chi tiết trong repo dotnet Roslyn trên GitHub :

Các thuộc tính tự động hiện có thể được khai báo mà không cần bộ định thời.

Trường hỗ trợ của thuộc tính tự động chỉ getter được khai báo ngầm là chỉ đọc (mặc dù điều này chỉ quan trọng đối với mục đích phản ánh). Nó có thể được khởi tạo thông qua trình khởi tạo trên thuộc tính như trong ví dụ trên. Ngoài ra, một thuộc tính chỉ getter có thể được gán cho phần thân hàm tạo của kiểu khai báo, điều này khiến giá trị được gán trực tiếp cho trường cơ sở:

Đây là cách diễn đạt các kiểu ngắn gọn hơn, nhưng lưu ý rằng nó cũng loại bỏ sự khác biệt quan trọng trong ngôn ngữ giữa các kiểu có thể thay đổi và không thể thay đổi: thuộc tính tự động chỉ có sẵn nếu bạn sẵn sàng làm cho lớp của mình có thể thay đổi và do đó, sự cám dỗ để mặc định điều đó thật tuyệt. Giờ đây, với thuộc tính tự động chỉ dành cho getter, sân chơi đã được san bằng giữa có thể thay đổi và bất biến.

và trong Đặc tả ngôn ngữ dự thảo C # 6.0 (NB: Đặc tả ngôn ngữ là cuối cùng theo như Microsoft có liên quan, nhưng nó vẫn chưa được chấp thuận làm tiêu chuẩn EMCA / ISO , do đó là 'bản nháp'):

Các thuộc tính được triển khai tự động

Thuộc tính được triển khai tự động (hay viết tắt là thuộc tính tự động), là một thuộc tính không trừu tượng không ngoại lệ với phần thân của trình truy cập chỉ có dấu chấm phẩy. Thuộc tính tự động phải có bộ truy cập nhận và có thể tùy chọn có bộ truy cập đã đặt.

Khi một thuộc tính được chỉ định là thuộc tính được triển khai tự động, thì trường sao lưu ẩn sẽ tự động có sẵn cho thuộc tính và các trình truy cập được triển khai để đọc và ghi vào trường sao lưu đó. Nếu thuộc tính tự động không có bộ truy cập đã đặt, trường hỗ trợ được coi là chỉ đọc (Readonly fields). Cũng giống như trường chỉ đọc, thuộc tính tự động chỉ getter cũng có thể được gán trong phần thân của hàm tạo của lớp bao quanh. Nhiệm vụ như vậy chỉ định trực tiếp cho trường hỗ trợ chỉ đọc của thuộc tính.

Một thuộc tính tự động có thể tùy chọn có một property_initializer, được áp dụng trực tiếp vào trường hỗ trợ như một variable_initializer (Trình khởi tạo biến).


1
Đây là thiết kế ngu ngốc. Đây sẽ là lỗi thời gian biên dịch nếu được đặt tại vị trí nơi thuộc tính được coi là chỉ đọc.
Shiv

Điều kỳ lạ đối với tôi là vẫn có lỗi trình biên dịch thông báo CS0200 C# Property or indexer cannot be assigned to -- it is read onlykhi sử dụng thuộc tính thông thường. "Thuộc tính tự động chỉ Getter" có được coi là chỉ đọc hay không?
Kyle Delaney

24

Đây là một tính năng mới trong C # 6 cho phép bạn tạo các thuộc tính chỉ đọc và khởi tạo các giá trị của chúng từ hàm tạo (hoặc nội dòng khi bạn khai báo chúng).

Nếu bạn cố gắng thay đổi giá trị của thuộc tính này bên ngoài hàm tạo, nó sẽ gây ra lỗi biên dịch cho bạn.

Nó ở chế độ chỉ đọc theo nghĩa là một khi bạn khởi tạo giá trị của nó (nội dòng hoặc bên trong hàm tạo), bạn không thể thay đổi giá trị của nó.


Vậy, lời giải thích là gì? Định nghĩa của getter là gì?
Noam B.

16

Nếu không thể khởi tạo thuộc tính chỉ đọc từ hàm tạo (hoặc bộ khởi tạo thuộc tính tự động), thì nó sẽ vô dụng, vì nó sẽ luôn trả về giá trị mặc định cho kiểu của nó (0 đối với số, null đối với loại tham chiếu ). Ngữ nghĩa giống nhau được áp dụng cho các trường chỉ đọc trong tất cả các phiên bản C #.

Để xác định một thuộc tính chỉ getter đúng (không thể được khởi tạo từ phương thức khởi tạo), bạn cần chỉ định những gì nó trả về như một phần của định nghĩa:

public int Foo { get { return 5; } }

Hay ngắn gọn hơn trong C # 6:

public int Foo => 5;

Không hoàn toàn đúng, thuộc tính chỉ đọc rất hữu ích để đóng gói một số điều kiện trong mã của bạn. Bạn có thể viết một câu lệnh if và gần như bất kỳ mã để đánh giá tài sản hoặc điều kiện khác và trả về một giá trị thích hợp mỗi khi bạn đọc tài sản
sebagomez

3
@sebagomez: Tôi không chắc mình hiểu ý bạn - đó không phải là những gì tôi đã chứng minh trong ví dụ của mình?
Douglas

5

"Các thuộc tính được triển khai tự động chỉ đọc"

Trước hết, tôi muốn làm rõ rằng tài sản như

public string FirstName { get; }

Được gọi là "thuộc tính được triển khai tự động chỉ đọc"

Để xác minh điều này, bạn có thể chạy và kiểm tra đoạn mã trên bằng Visual Studio. Nếu bạn thay đổi phiên bản ngôn ngữ từ C # 6.0 sang C # 5.0 thì trình biên dịch sẽ ném ra ngoại lệ sau Tính năng 'thuộc tính được triển khai tự động chỉ đọc' không khả dụng trong C # 5. Vui lòng sử dụng phiên bản ngôn ngữ 6 trở lên.

để thay đổi phiên bản ngôn ngữ C # hãy truy cập vào đây

Bây giờ tôi đang đến với câu hỏi thứ hai của bạn

“Đây chỉ là getter. Nhưng khi tôi xây dựng một hàm tạo, tôi có thể thay đổi giá trị ”

Microsoft giới thiệu “các thuộc tính được triển khai tự động chỉ đọc” trên logic của chỉ đọc. Như chúng ta biết rằng từ khóa “chỉ đọc” có sẵn từ C # 1.0. chúng tôi sử dụng “chỉ đọc” từ khóa như sửa đổi trên một lĩnh vực và lĩnh vực có thể được gán trong 2 cách , hoặc tại thời điểm kê khai hoặc trong một constructor trong lớp cùng.

Theo cách tương tự, giá trị của "thuộc tính được triển khai tự động chỉ đọc" có thể được chỉ định theo 2 cách

Cách 1 (tại thời điểm khai báo):

public string FirstName { get; } = "Banketeshvar";

Way2 (trong một hàm tạo trong cùng một lớp)

Person()
{
 FirstName  = "Banketeshvar";
}

Thuộc tính hoàn toàn chỉ đọc

Nếu bạn đang tìm kiếm thuộc tính Readonly hoàn toàn thì hãy đi tìm

public string FullName => "Manish Sharma";

bây giờ bạn không thể gán giá trị của đề xuất “FullName” từ hàm tạo. Nếu bạn cố gắng làm điều đó, nó sẽ ném ra các ngoại lệ sau

“Không thể gán thuộc tính hoặc trình chỉ mục 'Person.FullName' - nó chỉ được đọc”


2
lưu ý rằng FullName => "foo bar" sẽ được đánh giá MỖI LẦN.
Sáu

4

Tính năng thuộc tính tự động đã được thêm vào ngôn ngữ trong phiên bản C # 3.0. Nó cho phép bạn xác định một thuộc tính mà không cần bất kỳ trường hỗ trợ nào, tuy nhiên bạn vẫn cần sử dụng hàm tạo để khởi tạo các thuộc tính tự động này thành giá trị không mặc định. C # 6.0 giới thiệu một tính năng mới được gọi là bộ khởi tạo thuộc tính tự động cho phép bạn khởi tạo các thuộc tính này mà không cần hàm tạo như Dưới đây:

Trước đây, một hàm tạo là bắt buộc nếu bạn muốn tạo các đối tượng bằng thuộc tính tự động và khởi tạo thuộc tính tự động thành một giá trị không mặc định như bên dưới:

public class MyClass
{
    public int Foo { get; }

    public Foo(int foo)
    {
        Foo = foo;
    }
}

Bây giờ trong C # 6.0, khả năng sử dụng bộ khởi tạo với thuộc tính tự động có nghĩa là không cần mã khởi tạo rõ ràng.

public string Foo { get; } = "SomeString";

public List<string> Genres { get; } = new List<string> { "Comedy", "Drama" };

Bạn có thể tìm thêm thông tin về điều này tại đây


1

Một biến được khai báo readonlycó thể được viết trong một hàm tạo, nhưng trong các ngôn ngữ tôn trọng thuộc tính, không thể sửa đổi sau khi hàm tạo trả về. Bộ định tính đó được cung cấp như một tính năng ngôn ngữ vì nó thường cần thiết cho các trường có giá trị sẽ thay đổi dựa trên các tham số của hàm tạo (có nghĩa là chúng không thể được khởi tạo trước khi khởi chạy hàm tạo) nhưng sẽ không phải thay đổi sau khi các hàm tạo trả về, nhưng nó đã chỉ có thể sử dụng cho các biến được hiển thị dưới dạng trường. Trong readonlynhiều trường hợp, ngữ nghĩa của các trường-đủ điều kiện sẽ là hoàn hảo cho các thành viên công cộng ngoại trừ việc các lớp thường hiển thị các thành viên - thậm chí là bất biến - dưới dạng thuộc tính thay vì trường.

Cũng giống như các thuộc tính tự động đọc-ghi tồn tại để cho phép các lớp hiển thị các thuộc tính có thể thay đổi dễ dàng như các trường thông thường, các thuộc tính tự động chỉ đọc tồn tại để cho phép các lớp hiển thị các thuộc tính bất biến dễ dàng như readonlycác trường đủ tiêu chuẩn. Cũng giống như readonlycác trường-đủ điều kiện có thể được viết trong một hàm tạo, cũng như vậy với các thuộc tính chỉ nhận.

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.