2012-11-28 82 views
9

我試圖找出解決這個問題的好方法。我有一個客戶類實現了ICustomer接口。這個接口有很多屬性:C#中的內部屬性設置器

public interface ICustomer 
{ 

    string FirstName {get; set;} 
    string LastName {get; set;} 
} 

我只希望某些類能夠設置這些屬性,但是,即項目中的那些類。所以我想關於做二傳手internal

public class Customer : ICustomer 
{ 

    string FirstName {get; internal set;} 
    string LastName {get; internal set;} 
} 

我想,以紀念然而界面二傳手內部,所以沒有機會實現人與ICustomer人大會以外的修改這些屬性。有沒有一個好的方法來做到這一點?

回答

16

接口中的屬性應該是隻讀的。即使接口中沒有定義接口,實現接口的具體類也可以擁有setter。

public interface ICustomer 
{ 
    string FirstName { get; } 
    string LastName { get; } 
} 

public class Customer : ICustomer 
{ 
    public string FirstName { get; internal set; } 
    public string LastName { get; internal set; } 
} 

如果它真的很重要的二傳手通過接口暴露出來,而不是接口被完全只讀,你可以使用這樣的事情:

public interface IReadCustomer 
{ 
    string FirstName { get; } 
    string LastName { get; } 
} 

internal interface IWriteCustomer 
{ 
    string FirstName { set; } 
    string LastName { set; } 
} 

internal interface IReadWriteCustomer : IReadCustomer, IWriteCustomer 
{ } 

public class Customer : IReadWriteCustomer 
{ 
    private string _firstName; 
    private string _lastName; 

    public string FirstName 
    { 
     get { return _firstName; } 
     internal set { _firstName = value; } 
    } 
    public string LastName 
    { 
     get { return _lastName; } 
     internal set { _lastName = value; } 
    } 

    string IReadCustomer.FirstName 
    { 
     get { return FirstName; } 
    } 

    string IReadCustomer.LastName 
    { 
     get { return LastName; } 
    } 

    string IWriteCustomer.FirstName 
    { 
     set { FirstName = value; } 
    } 

    string IWriteCustomer.LastName 
    { 
     set { LastName = value; } 
    } 
} 
+0

感謝您的協助。但是,如果我這樣做,而消費階層使用ICustomer,則無法進入設定者。 – larryq

+2

@larryq這是整個觀點,因爲界面並沒有提交給setter。如果你想實現第二個內部接口,你可以添加setter。我經常有一系列的接口:這是一個真實的例子:'IDimensionedMap'只提交2D實體的維度;具有可讀屬性的IReadMap',只讀或計算映射的'IReadMap:IDimensionedMap',然後是'IWriteMap:IReadMap'。但這是一個複雜的可擴展實用程序類。 (如果你很好奇,這些是2d希爾伯特空間,不是字典) – SAJ14SAJ

+1

@larryq雖然我不確定是否需要它,但我添加了一個替代實現,其中接口定義了一個內部set方法。 – Servy

6

我會就像在接口中將該setter標記爲內部的那樣,所以沒有人有機會實現ICustomer,並且會議外的某個人修改了這些屬性。有沒有一個好的方法來做到這一點?

不是。屬性成員是總是公共,不幸的是。此外,在接口上指定部分屬性的訪問級別會變得很痛苦,IIRC。你可以是這樣的:

public interface ICustomer 
{ 
    string FirstName { get; } 
    string SecondName { get; } 
} 

internal interface ICustomerWithSetMethods : ICustomer 
{ 
    void SetFirstName(string name); 
    void SetLastName(string name); 
} 

public class Customer : ICustomerWithSetMethods 

然後從它會像Customer只實現ICustomer,但是從裏面代碼會看到它實現ICustomerWithSetMethods

不幸的是,不發揮很好,如果你的API需要聲明,你倒是真的剛剛宣佈的ICustomer返回類型的任何公共方法,但實際上你會知道,它總是ICustomerWithSetMethods

假設你仍然要允許多種實現,你可能去一個抽象類,而不是:

public abstract class CustomerBase 
{ 
    public abstract string FirstName { get; } 
    public abstract string LastName { get; } 

    internal abstract void SetFirstName(string name); 
    internal abstract void SetLastName(string name); 
} 

現在我們有輕微的古怪,沒有人大會以外的可以延長你的CustomerBase,因爲有是他們必須重寫的抽象方法,他們甚至不能請參閱 - 但這意味着您可以在API中的任何地方使用CustomerBase

這是我們最後在日曆系統中使用的Noda Time的方法 - 當我第一次提出這個計劃的時候我是blogged about it。我一般認爲更喜歡抽象類的接口,但這裏的好處是顯着的。

+0

你錯過了名字和姓氏的類型和範圍 –

+0

@JonB:所以我做到了。修正了,謝謝。 –

+0

@JonSkeet我同意你的方法,但是隨着時間的推移,可維護性將會成爲一個問題,我通常實現接口和抽象基類。它有一些額外的輸入,但Resharper這樣的工具使它更容易,這意味着當你有一個複雜的對象系列時,你可以有多個抽象實現,可能會在你自己的代碼庫之外進行擴展。 – SAJ14SAJ