[英]if using an interface should a class always strictly implement an interface
提出這個問題的更好方法是如下例子:這兩種方法的優點和缺點是什么? 一個總是優於另一個或在特定情況下? 如果使用Approach1,使用界面會沒有意義嗎? 既然任何人都可以訪問公共方法呢?
public interface IDoSomething
{
void Method1(string operation, User user, string category)
void Method2(string operation, User user)
void Method3(string operation)
}
//Approach1
Class A: IDoSomething
{
public void Method1(string operation, User user, string category)
{
//do some db logic here...
}
public void Method2(string operation, User user)
{
Method1(operation, user, "General");
}
public void Method3(string operation)
{
Method1(operation, User.GetDefaultUser(), "General");
}
}
要么
//Approach2
Class A: IDoSomething
{
void IDoSomething.Method1(string operation, User user, string category)
{
//do some logic here...
}
void IDoSomething.Method2(string operation, User user)
{
(this as IDoSomething).Method1(operation, user, "General");
}
void IDoSomething.Method3(string operation)
{
(this as IDoSomething).Method1(operation, User.GetDefaultUser(), "General");
}
}
您正在尋找描述第二種方法的短語是顯式接口實現 。 就個人而言,我大部分時間都不會使用它。 您需要以不同的方式實現具有相同成員簽名的不同接口,或者如果您希望限制某些成員僅在處理接口類型的表達式時可見時,這很有用...但是如果對於無論你的調用者具有什么樣的具體類型,並且需要調用一些特定於類型的方法和一些接口方法。 如果不將this
方法強制轉換為接口類型,您甚至無法在同一個類中看到顯式實現的方法。
顯式接口實現還意味着您不能覆蓋接口方法 - 您必須在任何子類中重新實現接口。 基本上它最終會變得非常復雜 - 所以如果可能的話我會避免它。
最后要注意的是:顯式接口實現在C#4中的dynamic
也很糟糕 。
方法1是在C#中實現接口的自然方式。 如果你寫一個圖書館,這就是你的客戶所期望的; 如果您自己使用該類,則在調用方法時可以節省大量的時間。
如果您有充分的理由 ,請使用方法2( 顯式接口實現 )。 好的理由可能包括
它(在某種程度上)是一種品味問題。 主要區別在於,如果進行顯式實現,除非首先將對象強制轉換為接口類型,否則無法調用這些方法:
A item = new A();
item.Method2(operation, user); // will not compile
(item As IDoSomething).Method2(operation, user); // works well
如果您不希望接口實現由於某種原因“混亂”IntelliSense中的成員列表,則此方法很有用。
我個人傾向於使用隱式方法,除非有特定的理由“隱藏”接口實現。
兩者的一個非常常見的組合是在實現IEnumerable<T>
。 由於IEnumerable<T>
繼承自IEnumerable
,因此您必須實現IEnumerable<T>.GetEnumerator()
和IEnumerable.GetEnumerator()
。 由於它們具有不同的返回類型,但匹配的參數列表(空),最多只能隱式實現一個。
最常見的模式是實現通用版本:
public IEnumerator<T> GetEnumerator()
{
//some code that returns an appropriate object.
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();//return the result of the other call.
}
現在,一個人不需要隱式,或者一個人可以(在顯式實現中使用一點點),反之亦然。 但是,由於以下原因,這很方便:
IEnumerator<T>
想要的和調用代碼IEnumerator
(因為這是隱式轉換),並且因此是最有用的。 現在,那種情況是我們被迫使用顯式接口。 對於一個案例的例子,我們可以選擇,考慮編寫一個包含List<T>
的只讀列表並實現IList<T>
。
我們所要做的就是將讀取操作委托給包裝列表,並且不支持寫入操作,例如:
public T this[int idx]
{
get
{
return _inner[idx];
}
set
{
throw new NotSupportedException("Read only list.");
}
}
public int Count
{
get
{
return _inner.Count;
}
}
public void Add(T item)
{
throw new NotSupportedException("Read only list.");
}
public bool IsReadOnly
{
get
{
return false;
}
}
等等。 但是,這對於使用具體類型的對象的人來說不是很有用,我們有很多成員要么返回相同的結果( IsReadOnly
),要么總是拋出異常。 雖然通過其接口使用類的代碼必須能夠調用這些方法和屬性,但在具體類中這樣做是沒有價值的。 因此我們可以這樣做:
public T this[int idx]
{
get
{
return _inner[idx];
}
}
T IList<T>.this[int index]
{
get { return this[index]; }
set { throw new NotSupportedException("Collection is read-only."); }
}
public int Count
{
get
{
return _inner.Count;
}
}
void ICollection<T>.Add(T item)
{
throw new NotSupportedException("Read only list.");
}
bool ICollection<T>.IsReadOnly
{
get
{
return false;
}
}
現在,當我們完全實現IList<T>
我們還為具體類的用戶提供了一個更清潔,更有用的界面(在一般而不是c#特定的“界面”意義上)。
請注意,這正是基於它通常更有意義隱含的原因構建的:我們已經讓所有這些成員對於具體類的用戶來說更加尷尬(這樣的代碼必須首先強制轉換為IList<T>
)。 這在這里很好,因為這種笨拙的代碼的唯一結果是毫無意義或危險,並且讓糟糕的想法更難做是一件好事。 如果這種尷尬只是阻礙了,那將是另一回事。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.