[英]Type constraints in interface apply to base class
我有一個基類定義了這樣的泛型方法:
public class BaseClass
{
public T DoSomething<T> ()
{ ... }
}
由於這個類是由第三方提供的,並沒有附帶接口,因此我定義了一個接口,用於定義該類中實際需要的方法。 這樣我就可以得到松散的耦合,並且實際上可以用其他東西來交換第三方類。 對於此示例,請考慮以下接口:
public interface ISomething
{
T DoSomething<T> ()
where T : Foo;
}
如您所見,它定義了相同的方法,但也對類型參數應用了類型約束,該類型參數來自與此無關的其他一些要求。
接下來,我定義了BaseClass
的子類型,它也實現了ISomething
。 該類將用作接口背后的通常實現 - 而接口將是應用程序的其余部分將訪問的內容。
public class Something : BaseClass, ISomething
{
// ...
}
由於BaseClass
的DoSomething
已經支持任何類型參數T
,它應該特別支持一個類型參數,它是Foo
的子類型。 因此可以預期BaseClass
的子類型已經實現了接口。 但是我收到以下錯誤:
方法'BaseClass.DoSomething()'的類型參數'T'的約束必須匹配接口方法'ISomething.DoSomething()'的類型參數'T'的約束。 請考慮使用顯式接口實現。
現在,我有兩種可能性; 第一個是做錯誤建議並明確地實現接口。 第二種是使用new
隱藏基本實現:
// Explicit implementation
T ISomething.DoSomething<T> ()
{
return base.DoSomething<T>();
}
// Method hiding
public new T DoSomething<T>()
where T : Foo
{
return base.DoSomething<T>();
}
兩者都有效,雖然我可能更喜歡第二種解決方案,以保持方法可以從類本身訪問。 但是它仍然留下以下問題:
當基類型使用less-strict(read:none)類型約束實現它時,為什么必須重新實現該方法? 為什么該方法需要完全按原樣實現?
編輯:為了給方法更多的意義,我將返回類型從void
更改為T
在我的實際應用程序中,我有泛型參數和返回值。
嘗試使用組合而不是繼承來實現Something
:
public class Something : ISomething
{
private readonly BaseClass inner = ...;
void DoSomething<T>() where T : Foo
{
inner.DoSomething<T>();
}
}
當然,給定的代碼可以編譯並安全運行:
當Something
實例被輸入Something
或BaseClass
,編譯器將允許T
任何類型,而當同一實例被輸入為ISomething
,它將只允許繼承Foo
類型。 在這兩種情況下,您都可以照常進行靜態檢查和運行時安
實際上,上面的場景正是您明確實現ISomething
時會發生的情況。 那么讓我們看看我們可以為當前的事態做出什么樣的爭論。
對於:
反對:
考慮到上述情況以及此事實並非日常情況,恕我直言會得出的結論很明確:這可能會很好,但它肯定不會讓您不顧一切地實施它。
您可以使用下面的代碼獲得所需內容。 通過在接口defenition中包含type參數,您可以使其協變,這似乎滿足編譯器。 Base
類保持不變,您可以使用單個方法隱藏Base
實現並實現接口。
class Program
{
static void Main()
{
var something = new Something<Foo>();
var baseClass = (BaseClass)something;
var isomething = (ISomething<Foo>)something;
var baseResult = baseClass.DoSomething<Bar>();
var interfaceResult = isomething.DoSomething<Bar>();
var result = something.DoSomething<Bar>();
}
}
class Foo
{
}
class Bar : Foo
{
}
class BaseClass
{
public T DoSomething<T>()
{
return default(T);
}
}
interface ISomething<out T> where T : Foo
{
T DoSomething<T>();
}
class Something<T> : BaseClass, ISomething<T> where T : Foo
{
public new T DoSomething<T>()
{
return default(T);
}
}
或者如果你真的不想在實例化中指定Foo
class Program
{
static void Main()
{
var something = new Something();
var baseClass = (BaseClass)something;
var isomething = (ISomething)something;
var baseResult = baseClass.DoSomething<Bar>();
var interfaceResult = isomething.DoSomething<Bar>();
var result = something.DoSomething<Bar>();
}
}
class Foo
{
}
class Bar : Foo
{
}
class BaseClass
{
public T DoSomething<T>()
{
return default(T);
}
}
interface ISomething
{
T DoSomething<T>;
}
interface ISomething<S> : ISomething where S : Foo
{
new R DoSomething<R>() where R : Foo;
}
class Something : BaseClass, ISomething
{
public new T DoSomething<T>()
{
return default(T);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.