簡體   English   中英

Generics 鑄件

[英]Generics Casting

interface Base { ... }
class Sub : Base { ... }

class OtherBase<T> where T : Base { ... }
class OtherSub<T> : OtherBase<T> where T : Base { ... }

//...in some class
void Call<T>() where T : OtherBase<Base> { }

//...
Call<OtherSub<Sub>>(); //compile fails...

似乎在使用 generics 時,編譯器不會在泛型類型(OtherBase/OtherSub)中轉換內部泛型類型(Base/Sub)。 為什么會這樣?

更新:還請解釋上面和下面的區別(有效)

void Call<T>() where T : Base { }
//...
Call<Sub>();

禁止這種行為(稱為“通用方差”)是必要的,否則以下代碼將編譯:

List<string> strlist = new List<string>();
List<object> objlist = strlist;
objlist.Add(42);

我們在字符串列表中添加了一個數字。 不好。 (順便說一句,代碼將編譯為arrays而不是List s,因為 Java 出於某種原因允許這樣做;但是,這將引發運行時異常。)

不過,您可以在您的情況下避免這種情況:

static void Call<U, T>(T x) where U : Base where T : OtherBase<U> { }

並這樣稱呼它:

Call(new OtherSub<Sub());

C# 4.0 還為接口提供了通用差異 但是,它們的使用通常不是必需的。

您的問題與稱為方差/協方差的概念有關。 事實上,如果A繼承自B ,則Class<A>不是Class<B>

看這個例子:

Class<T>公開了一個公共方法foo(T param)

如果Class<A>Class<B> ,那么將Class<B>引用為Class<A>並調用foo(B param) (帶有B實例)的方法將調用foo(A param) . 而且B不是A

事實上, Class<A>只有在T僅在Class<T>中用作返回值時才能從Class<B>繼承。

這是通過 generics 接口的 out 關鍵字在 .NET 4 中強制執行的。 Class<T>因此可以實現IClass<out T>

Konrad 對如何修復代碼有很好的建議。 如果你想使用 C# 4 的方差,你可以這樣做:

interface IOtherBase<out T> where T : Base { }

class OtherBase<T> : IOtherBase<T> where T : Base { }
class OtherSub<T> : OtherBase<T> where T : Base { }

static void Call<T>() where T : IOtherBase<Base> { }

Call<OtherSub<Sub>>()會起作用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM