2010-07-22 6 views
19

Tôi đã nhìn thấy rất nhiều mã ví dụ được viết bằng một cái gì đó tương tự (xin vui lòng tha thứ cho cách khủng khiếp đóng hộp này là):Private 'đặt' trong C# - gặp khó khăn trong gói bộ não của tôi xung quanh nó

public class Test 
{ 
    public object Thingy { get; private set; } 
} 

Thật không may, những các loại ví dụ không bao giờ thực sự giải thích tại sao 'set' được đặt là riêng tư. Vì vậy, tôi chỉ tự hỏi nếu có một ví dụ tốt, phổ biến mà sẽ minh họa cho tôi tại sao một cái gì đó như thế này sẽ được sử dụng.

Tôi thấy nó - thuộc tính có thể chạy để xử lý thêm một số logic ngoài việc thiết lập trường đó. Tôi chỉ bối rối về cách nó sẽ được viện dẫn, và tại sao cách tiếp cận này sẽ được sử dụng chứ không phải là một phương thức setter chung chung.

Trả lời

24

Điều này sẽ xảy ra nếu bạn có thuộc tính mà bạn không muốn bất kỳ ai thiết lập mà là lớp học của bạn. Điều này có thể thuận tiện với id cơ sở dữ liệu. Lớp nội bộ có thể đặt nó nhưng bạn sẽ không muốn bất kỳ ai khác thay đổi nó. Vì vậy, bạn có thể cung cấp cho họ đọc truy cập nhưng không viết.

EDIT: Một điểm nữa là sử dụng những gì bạn đã cho thấy sẽ hữu ích cho các thuộc tính tự động. Thật không may với các thuộc tính tự động, bạn không thể chỉ xác định có được như vậy để tránh lộ một setter công khai nó chỉ được thực hiện riêng tư.

EDIT: Chỉ nghĩ rằng tôi sẽ ném vào một ví dụ. Thuộc tính tự động là rất tốt cho mã terse, sạch sẽ. Nhưng như bạn đã cho thấy có một giới hạn trong đó bạn phải có được và thiết lập. Vì vậy, trước khi nó giống như thế này cho một tài sản như bạn đã cho thấy:

public class Test 
{ 
    private object thingy; 
    public object Thingy 
    { 
     get { return thingy; } 
    } 
} 

Bây giờ chúng ta có thể loại bỏ tuyên bố riêng không cần thiết đó nhưng nó đòi hỏi cả hai. Vì vậy, hãy riêng tư để giải quyết vấn đề đó.

Tôi biết điều này là quá mức cần thiết về giải thích nhưng những điều khác nhau vẫn tiếp tục xuất hiện trong đầu tôi.

+1

Ah, tôi đã không nhận ra rằng cả nhận và đặt phải được khai báo cho thuộc tính tự động. Điều đó có ý nghĩa hơn rất nhiều. –

4

Riêng tư biến nó thành thuộc tính chỉ đọc. Một ví dụ phổ biến là nếu bạn có nhiều lớp học đi qua một đối tượng duy nhất, bạn không muốn một lớp khác có thể sửa đổi cá thể.

9

Ví dụ đơn giản; nó là một cách rẻ tiền để tạo ra một đối tượng "không thay đổi đủ" (để sử dụng trong luồng, trạng thái, vv). Nhưng cũng ở bất cứ nơi nào khách hàng chỉ cần không nên cần phải gán hoặc không thể tin cậy để chỉ định (chính xác).

Một ví dụ khác có thể là một danh sách:

public List<Foo> Items {get;private set;} 

vì chúng ta có thể gọi obj.Items.Add() vv, nhưng chúng tôi sẽ hiếm khi gán obj.Items = .... Tuy nhiên, ví dụ này thấm đẫm cần khởi rõ ràng trong các nhà xây dựng, và XmlSerializer ghét nó - phải trung thực cho các danh sách tôi chủ yếu sử dụng:

private readonly List<Foo> items = new List<Foo>(); 
public List<Foo> Items {get { return items;}} 

mà giải quyết được cả hai.

Một ví dụ khác, tương phản:

private readonly int foo; 
public int Foo {get{return foo;}} 

vs

private readonly int foo; 
public int Foo {get{return foo;} private set {foo=value;}} 

mô hình này có thể hữu ích trong serialization, ví dụ với DataContractSerializer (với việc bổ sung một số thuộc tính), vì serializers nhiều sẽ vẫn tìm kiếm người truy cập riêng. Điều này tránh cho chúng tôi phải trang trí trạng thái nội bộ nội bộ của chúng tôi (foo), nhưng cung cấp veneer riêng tư cho set.

Cuối cùng bất cứ điều gì có thể đường tránh và giao thông qua phản ánh, vì vậy tin set là chỉ nhằm mục đích tránh tình cờ thiệt hại cho dữ liệu.

+0

Điểm của bạn về danh sách và bộ nối tiếp được thực hiện tốt. Cảm ơn vì điều đó. :-) –

+0

+1! Mặc dù tôi đã phơi bày ReadOnlyCollection hoặc Bộ sưu tập chung chung thay vì Danh sách - xem http://blogs.msdn.com/b/codeanalysis/archive/2006/04/27/585476.aspx – TrueWill

2

Về cơ bản, đó là thuộc tính chỉ đọc. Nếu nó được viết đầy đủ (không phải là một tài sản tự động), bạn chỉ đơn giản là sẽ rời khỏi setter.

Hai ví dụ mà chủ yếu là giống nhau:

class Foo1 
{ 
    public int Id { get; private set; } 
    public Foo1() 
    { 
     Id = lastId ++; 
    } 
} 

class Foo2 
{ 
    private int _id; // could be readonly 
    public int Id { get { return _id; } } 
    public Foo2() 
    { 
     _id = lastId ++; 
    } 
} 
1

Cú pháp này cho phép bạn để cung cấp một tài sản công phải đối mặt đó xuất hiện read-only cho người tiêu dùng của API của bạn, nhưng trong nội bộ có thể được thay đổi. Bằng cách tự động triển khai theo cách này, bạn tránh phải viết mã soạn sẵn như một bộ tách riêng biệt hoặc trường sao lưu cho giá trị và bạn rời khỏi phòng trong thiết kế của mình để thêm thuật toán đặt riêng nếu được coi là cần thiết tại một số điểm trong tương lai mà không cần phải quyết định ngay.

0

Đây chỉ là laziness xuất phát từ các thuộc tính tự động. Trước khi các thuộc tính tự động được đưa vào xung quanh, mọi người sẽ triển khai trình thu thập và bỏ qua trình thiết lập cho các thuộc tính có nghĩa là chỉ đọc.

public class Test 
{ 
    private /*readonly*/ Type _thingy; 
    public Type Thingy { get { return _thingy; } } 
} 

Hy vọng rằng, C# 5 sẽ cho phép bạn tạo thuộc tính tự động chỉ với trình thu thập - vì đó là những gì mọi người muốn. (Chúng cũng nên làm cho các bộ cài đặt chỉ đọc trong các đạo cụ tự động, tôi cần điều đó một cách tồi tệ)

+0

nếu mục đích là giới thiệu 'chỉ đọc', sau đó tốt; nhưng như là một tổng quát hơn "chỉ có thể thay đổi * nội bộ *" (mà là một nhu cầu chung) tôi sẽ phải không đồng ý; có rất ít lợi ích trong việc có một trường rõ ràng trong trường hợp đó. –

+0

Vâng, giới thiệu chỉ đọc là những gì tôi có ý nghĩa. Tôi chỉ muốn giảm cú pháp để nói 'int Thingy {get; readonly set = 100; } ', hoặc một cái gì đó như thế. –

1

bộ riêng tư rất tiện dụng cho các loại giá trị không thay đổi đơn giản.

struct Point 
{ 
    public int X { get; private set; } 
    public int Y { get; private set; } 
    public Point(int x, int y) 
    { 
     this = default(Point); 
     X = x; 
     Y = y; 
    } 
} 
+0

Tôi nghĩ bạn có thể thêm ': this()' vào khai báo hàm tạo thay vì gán 'this = default (Point)'? –

2

Tôi đã nhìn thấy này được sử dụng với thiết kế:

public class whatever 
{ 
    public string WhateverId { get; private set; } 

    public static whatever Create(string whateverId) 
    { 
     return new whatever() { WhateverId = whateverId }; 
    } 
} 

Vì vậy, bạn tạo ra bất cứ điều gì lớp, nhưng sau khi nó được tạo ra id không thể thay đổi vì nó có thể phá vỡ mọi thứ được kết nối với nó.

bộ riêng tư chỉ cung cấp cú pháp khởi tạo đơn giản, tôi thích kiểu này cho một số trường hợp.

Ngoài ra có thể được sử dụng nếu nó thay đổi, nhưng bạn cần phải quản lý nó khi có thay đổi

public void SetWhateverId(string whateverId) 
{ 
    DisconnectAllCurrentWhateverIdReferences(); 
    WhateverId = whateverId; 
    ReconnectAllPreviousWhateverIdReferences(); 
} 
0

Để trả lời câu hỏi của một kịch bản phổ biến nơi này có thể được sử dụng ... Trong một mô hình MVP, nếu mẫu của bạn cho thấy một số thuộc tính cho Presenter của bạn tôi sẽ viết

public string Bazinga { get; private set; } 

Bây giờ, mô hình có thể thay đổi giá trị này nhưng các lớp khác mà sử dụng nó không thể.