2012-03-02 23 views
13

Người quản lý của tôi đã hỏi tôi có thực hành tốt hay không để sử dụng tài sản với người đặt cược, nhưng không có người khởi xướng.Có lý do nào để có tài sản không có người trả tiền không?

public class PropertyWrapper 
{ 
    private MyClass _field; 

    public MyClass Property 
    { 
     set { _field = value; } 
    } 

    public string FirstProperty 
    { 
     get { return _field.FirstProperty; } 
    } 

    public string SecondProperty 
    { 
     get { return _field.SecondProperty; } 
    } 
} 

Anh ấy sẽ sử dụng các thuộc tính khác để hiển thị các thuộc tính từ trường riêng tư, do người đặt này đặt.

Đề xuất của tôi là chỉ sử dụng trường riêng tư và đặt nó trong hàm tạo, hoạt động tốt trong trường hợp này. Nếu tôi cần phải có một đối tượng được xây dựng đầu tiên (thậm chí có thể sử dụng đa hình), tôi vẫn thích phương thức Load hơn là một thuộc tính getter-less.

Nhưng tôi quan tâm. Cả hai chúng tôi đều rất quan tâm đến những thực tiễn tốt nhất và cố gắng đảm bảo mã của chúng tôi được chuẩn bị. Có ai có bất kỳ bài viết chính thức về tài sản getter-ít hơn? Hoặc tốt hơn vẫn là một ví dụ về cách sử dụng này trong .NET Framework?

+2

Không có gì sai với nó, nhưng nó không phổ biến. Tại sao có một tài sản cho điều này nếu bạn chỉ có thể thiết lập nó? – Oded

+3

Xem http://stackoverflow.com/questions/4695551/write-only-properties-whats-the-point – kaj

+0

@KAJ cảm ơn bạn! Tôi không tìm thấy cái đó trong tìm kiếm của tôi lúc đầu. – Connell

Trả lời

16

bài viết chính thức: Design Guidelines for Developing Class Libraries -> Member Design Guidelines -> Property Design

Không cung cấp thiết chỉ tính.

Nếu không thể cung cấp cho trình khởi động thuộc tính, hãy sử dụng phương pháp để thực hiện chức năng thay thế. Tên phương thức nên bắt đầu bằng Set theo sau là tên thuộc tính. Ví dụ: AppDomain có một phương thức được gọi là SetCachePath thay vì có thuộc tính chỉ thiết lập được gọi là CachePath.

2

Không có gì sai khi có thuộc tính getter-less, nếu đó là những gì làm cho mã của bạn dễ hiểu nhất và có thể duy trì. Tuy nhiên, những trường hợp tốt cho điều này có lẽ rất hiếm.

Điều tốt nhất tôi từng sử dụng thuộc tính getter-less là dành cho các lớp kiểm tra đơn vị có thuộc tính có các bộ định vị không thể tiếp cận. Ví dụ:

public class MyClass 
{ 
    public int MyId { get; protected set; } 
} 

public class MyClass_Test : MyClass 
{ 
    public int MyId_Set 
    { 
     set { MyId = value; } 
    } 
} 

Bằng cách này tôi có thể sử dụng một MyClass_Test trong các thử nghiệm đơn vị và tiền đặt một giá trị để MyId với khả năng kiểm tra đơn vị một phương pháp cụ thể.

Ngoài ra, để đáp ứng trực tiếp với ví dụ của bạn, sử dụng một private get có lẽ sẽ là cách tốt hơn xung quanh nó: không có gì

public class PropertyWrapper 
{  
    public MyClass Property { private get; set; } 

    public string FirstProperty 
    { 
     get { return Property.FirstProperty; } 
    } 

    public string SecondProperty 
    { 
     get { return Property.SecondProperty; } 
    } 
} 
+1

Thêm một số khả năng vào lớp chỉ để kiểm tra đơn vị có vẻ là một mùi mã. –

+0

Tôi đoán tôi có thể xác định rằng lớp '_Test' chỉ tồn tại trong ngữ cảnh của phép kiểm thử đơn vị - nó cho phép tôi thiết lập trạng thái của đối tượng và kiểm tra từng phương thức đơn lẻ. – eouw0o83hf

+0

Tôi đang nói về việc đặt setter 'MyClass.MyId' được bảo vệ. Nếu đó là sẽ được sử dụng chỉ để thử nghiệm đơn vị - đó là IMHO không phải là một thiết kế tốt. –

0

Ther để nói rằng bạn không thể làm điều này nhưng nó có vẻ hơi kỳ quặc. Tôi sẽ có một tài sản riêng tư và một phương pháp để đặt nó theo nghĩa là

private string _test; 

public void SetTest(string test) 
{ 
_test = test; 
} 
0

Bạn phải nhớ lý do tại sao các thuộc tính tồn tại. Chúng thay thế mẫu sau đây

class Foo 
{ 
    private Bar _bar; 

    public Bar GetBar() 
    { 
     return _bar; 
    } 

    public void SetBar(Bar bar) 
    { 
     _bar = bar; 
    } 
} 

Trong khi có thuộc tính không có Setter có vẻ kỳ quặc với tôi, tôi không nghĩ rằng phương pháp Set không có phương thức Get trông lạ cả.

Trong thực tế, tôi khá chắc chắn rằng các thuộc tính là đường cú pháp và được viết lại dưới dạng phương thức get/set. Hoặc ít nhất là rất gần.

+0

Tôi cùng ý kiến. 'SetBar' mà không có một' GetBar' có vẻ bình thường, nhưng đây là những gì trình biên dịch làm cho một thuộc tính C# anyway! – Connell

3

Tôi không có bài viết hoặc ví dụ chính thức nào .. chỉ có ý kiến.

Và theo tôi, một tài sản không thể đọc được là một con thú sẽ tức giận và bối rối.

Nó đi kèm với mục đích. Một tài sản nói "Tôi định cho phép người tiêu dùng đọc tôi, và thậm chí có thể viết thư cho tôi". Một hàm có tên là "SetSomeAttribute" khai báo một ý định chỉ ghi.

Còn có toàn bộ dữ liệu của tôi, vậy tại sao tôi không thể đọc lại điều đó.

Vì vậy, theo ý kiến ​​của tôi, không bao giờ có lý do chính đáng để sử dụng thuộc tính chỉ ghi.

+0

Một ví dụ hay mà tôi nghĩ đến là một thứ liên quan đến mật khẩu. Có thể có cấu trúc dữ liệu thông tin xác thực cho phép bạn đọc/ghi tên người dùng nhưng mật khẩu chỉ được đặt. Nó có thể có phương pháp nội bộ để so sánh nó với một cá thể khác (tức là phương thức được lưu trữ với các giá trị chính xác) để xác định nội bộ nếu nó hợp lệ hoặc có thể có tùy chọn truy cập công khai một băm. – Servy

+0

@Servy: Tôi không chắc chắn tôi làm theo. Nếu một thuộc tính là chỉ ghi, thì NOBODY, thậm chí không một thể hiện khác của lớp/struct đó có thể đọc thuộc tính. Vậy so sánh này sẽ diễn ra như thế nào? Trong trường hợp này, tôi sẽ lựa chọn phương thức .SetPassword() thay vì thuộc tính chỉ ghi và so sánh các thuộc tính công khai .Hash. –

+0

Vâng, mã trong setter rõ ràng sẽ cần phải lưu trữ nó trong một số phương tiện lưu trữ riêng để lớp có thể truy cập nội bộ nó; và thuộc tính được tạo tự động không có getter rõ ràng là vô nghĩa (và thậm chí có thể chỉ được loại bỏ bởi trình biên dịch). Nó sẽ cơ bản giống như có một phương thức setPassword, tôi đồng ý. Tôi không nói điều này sẽ tốt hơn, chỉ đơn thuần là đây là một trường hợp hiếm hoi mà tôi sẽ không phản đối nếu tôi thấy một thành viên trong nhóm thực hiện nó. – Servy

8

Xem xét các câu hỏi là: Có ai có bất kỳ bài viết chính thức nào về các thuộc tính không phải trả tiền ít hơn không? Hoặc tốt hơn vẫn là một ví dụ về cách sử dụng này trong .NET Framework? và không phải về ý kiến; Tôi đã viết một ứng dụng test nhanh để đọc qua tất cả các thuộc tính của tất cả các loại của tất cả các assembly được nạp trong một ứng dụng giao diện điều khiển mặc định:

foreach (var assem in AppDomain.CurrentDomain.GetAssemblies()) 
{ 
    foreach (var type in assem.GetTypes()) 
    { 
     foreach (var prop in type.GetProperties()) 
     { 
      if (!prop.CanRead) 
       Console.WriteLine("Assembly: {0}; Type: {1}; Property: {2}", assem.FullName, type.Name, prop.Name); 
     } 
    } 
} 

Kết quả là:

hội: mscorlib , Phiên bản = 4.0.0.0, Văn hóa = trung lập, PublicKeyToken = b77a5c561934e089; Loại: FileIOAccess; Thuộc tính: PathDiscovery

Lắp ráp: mscorlib, Phiên bản = 4.0.0.0, Văn hóa = trung lập, PublicKeyToken = b77a5c561934e089; Loại: RedirectionProxy; Thuộc tính: ObjectMode

Vì vậy, có vẻ như khuôn khổ sử dụng nó một cách tiết kiệm. Tôi muốn đề nghị làm như vậy.

EDIT

Điều thú vị đủ, chạy cùng mã với trình gỡ lỗi kèm theo sản lượng nhiều kết quả hơn:

Assembly: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: FileIOAccess; Property: PathDiscovery 
Assembly: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: RedirectionProxy; Property: ObjectMode 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: AxHost; Property: Site 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DataGridTextBoxColumn; Property: PropertyDescriptor 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DisplayedBandsData; Property: FirstDisplayedFrozenCol 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DisplayedBandsData; Property: FirstDisplayedFrozenRow 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DisplayedBandsData; Property: LastDisplayedFrozenCol 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DisplayedBandsData; Property: LastDisplayedFrozenRow 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DisplayedBandsData; Property: LastDisplayedScrollingRow 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ErrorProvider; Property: Site 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: WebBrowserBase; Property: Site 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: WebBrowser; Property: Site 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DropDownButton; Property: UseComboBoxTheme 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: GridErrorDlg; Property: Details 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: GridErrorDlg; Property: Message 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DropDownHolder; Property: ResizeUp 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: GridViewEdit; Property: DontFocus 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: GridViewEdit; Property: DisableMouseHook 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: MouseHook; Property: DisableMouseHook 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ManifestSignedXml; Property: Resolver 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ContainerProxy; Property: Bounds 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: RightToLeftProxy; Property: Bounds 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: TopDownProxy; Property: Bounds 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: BottomUpProxy; Property: Bounds 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ElementProxy; Property: Bounds 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: VerticalElementProxy; Property: Bounds 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: IconComparer; Property: SortOrder 
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: MultiPropertyDescriptorGridEntry; Property: PropertyValue 
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ConfigXmlDocument; Property: XmlResolver 
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ConfigXmlDocument; Property: InnerText 
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ProcessThread; Property: IdealProcessor 
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ProcessThread; Property: ProcessorAffinity 
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ConfigXmlAttribute; Property: InnerText 
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ConfigXmlAttribute; Property: InnerXml 
Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: AnonymousPipeServerStream; Property: ReadMode 
Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: AnonymousPipeClientStream; Property: ReadMode 
Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: ManifestSignedXml; Property: Resolver 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlResolver; Property: Credentials 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlNullResolver; Property: Credentials 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlSecureResolver; Property: Credentials 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlUrlResolver; Property: Credentials 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlUrlResolver; Property: Proxy 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlUrlResolver; Property: CachePolicy 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlReaderSettings; Property: XmlResolver 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlTextReader; Property: XmlResolver 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlValidatingReader; Property: XmlResolver 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DocumentXmlWriter; Property: NamespaceManager 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DocumentXmlWriter; Property: Navigator 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: DocumentXmlWriter; Property: EndNode 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlAttribute; Property: InnerText 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlAttribute; Property: InnerXml 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlDocument; Property: XmlResolver 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlDocument; Property: InnerText 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlUnspecifiedAttribute; Property: InnerText 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlUnspecifiedAttribute; Property: InnerXml 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlPreloadedResolver; Property: Credentials 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XslTransform; Property: XmlResolver 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlSchemaSet; Property: XmlResolver 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XmlSchemaValidator; Property: XmlResolver 
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089; Type: XsdValidator; Property: Context 
+0

Câu trả lời tuyệt vời! Tôi tự chạy mã này và có cùng kết quả. Tôi cũng đã cho người quản lý của tôi) Cảm ơn! – Connell

+0

Các kết quả này không cho biết liệu thuộc tính có thể truy cập công khai hay không - đó có thể là một số liệu thú vị. –

+0

Chỉ vì MS thực hiện nó không có nghĩa rằng nó là một thực hành âm thanh. –

-3

Bạn có thể có tài sản mà là ngăn nắp, và hơn mà bạn có thể thực hiện kiểm soát quyền truy cập đầy đủ, mà không có cú pháp _localVariable lộn xộn và thuộc tính.

ví dụ:

/// <summary> 
    /// Publicly readable, privately settable. 
    /// </summary> 
    public int FirstProperty { get; private set; } 

    /// <summary> 
    /// Entirely private 
    /// </summary> 
    private int SecondProperty { get; set; } 
+1

-1: câu trả lời không liên quan - câu hỏi là "là tài sản không có ích" và câu trả lời là "xem cách nhận". –

0

Họ có khả năng có thể được sử dụng cho dependency injection khi vì một lý do không phải xây dựng hay phương pháp tiêm làm việc cho bạn.

Nhưng tôi không thể tưởng tượng được trường hợp này.

0

Vâng, họ có thể sử dụng tốt cho các lĩnh vực tư nhân trong initializers đối tượng:

var obj = new MyClass 
{ 
    Prop1 = value1, 
    Prop2 = value2 
}; 

mà có thể là một cách khác để chỉ cần viết chúng như thông số nhà xây dựng:

var obj = new MyClass(value1, value2); 

Nhưng nếu có nhiều tham số (tùy chọn), các thuộc tính viết có thể có ích.

0

Như đã được đề xuất, tôi nghĩ câu trả lời là bất kỳ điều gì có ý nghĩa nhất trong bối cảnh của sự cố. Tôi có thể nghĩ đến hai lựa chọn thay thế để có một thuộc tính setter, có thể đáng để xem cái nào là ý nghĩa nhất:

  1. Xác định một phương thức riêng biệt chấp nhận một tham số.
  2. Xác định bộ thu thập luôn trả về cùng một giá trị (ví dụ: null). Cho dù điều này có ý nghĩa hay bất ngờ tùy thuộc vào ngữ cảnh.
Các vấn đề liên quan