[英]Why can't I cast a generic parameter with type constraint to the constrained type?
我習慣於使用接口,泛型並在真實環境中使用繼承來開發它們,同時嘗試使用並將其實現為我們即將開展的項目之一的新架構,並且我對於我對此感到困惑的泛型有疑問。
這對我自己來說更像是一個教育問題,因為我無法理解為什么.NET不允許這樣做。
如果我有一個泛型類(Of T As IA, T2 As A)
那么我有以下接口和實現基接口的類
Public Interface IA
Property A As String
End Interface
Public Interface IB
inherits IA
Property B As String
End Interface
Public Class GenericClass(Of T As IA, T2 As A)
'Should be list of IA?
Public list As New List(Of T)
Public Sub Add()
End Sub
End Class
因為我已經把T as IA
為什么在add方法中是Dim foo4 As T = New A()
不合法的時候
Dim foo1 As IA = New A()
Dim foo2 As T
Dim foo3 = Activator.CreateInstance(Of T2)()
Dim x As IA = foo2
Dim y As IA = foo3
list.Add(x)
list.Add(y)
以上都是? 這對於我來說已經成為一個學習曲線,但是我對於為什么我在邏輯上無法做到這一點感到非常困惑?
編輯:抱歉忘記了Class A
,錯誤信息請參見下文
Public Class A
Implements IA
Public Property A As String Implements IA.A
End Class
編輯2:錯誤輸入錯誤
“類型a的值不能轉換為T”
目前還不清楚你要做什么,但我注意到的一個問題是你似乎假設List<TypeThatImplementsIA>
在某種程度上可以與List<IA>
互換。 事實並非如此。 想象一下A
是一類飛鳥, IA
是由可以飛行的生物實現的,有人創造了GenericClass<Airplane, BlueJay)
。 盡管Airplane
和BlueJay
都是可以飛行的東西,但是人們無法將BlueJay
添加到List<Airplane>
。 框架中可以使用GenericType<DerivedType>
作為GenericType<BaseType>
的一種常見情況是使用IEnumerable<T>
。 原因是人們無法將T
存儲到IEnumerable<T>
中 - 只能讀出它們。 如果一個人期待一個IEnumerable<Animal>
並且一個人得到一個IEnumerable<MaineCoonCat>
,那么每當一個人想要讀一個Animal
,就會讀取一個MainCoonCat
實例,它繼承自Animal
,因此可以替代它。 IEnumerable<T>
這個特性稱為協方差 。
但是,這種行為存在限制,這是因為使用接口作為一種存儲位置(變量,參數等)與使用它作為約束之間存在差異。 對於每個非可空值類型,Runtime中實際上有兩個相關類型。 其中一個是真正的值類型,它沒有繼承的概念(但可以實現接口)。 另一種是從ValueType
派生的堆對象類型(后者又從Object
派生)。 大多數.net語言將隱式地將前一種類型轉換為后者,並允許代碼將后者明確地轉換為前者。 接口類型存儲位置只能保存對堆對象的引用。 an instance of that interface type. 這是顯著,因為這意味着,盡管它實現的接口的結構是轉換為該接口類型,這並不意味着該結構的實例 ,接口類型的實例。 協方差的前提是,例如IEnumerable<DerivedType>
返回的每個對象都可以直接用作BaseType
的實例, 而無需轉換 。 這種直接替代性適用於繼承的類類型,以及由類類型實現的接口。 它不適用於結構類型實現的接口,也不適用於沒有class
約束的泛型。 將類約束添加到泛型類類型參數將允許該類型參數參與協方差,但可能排除使用結構作為泛型類型參數。 請注意,除非有特殊理由期望接口將由結構實現(例如IComparable<T>
,在許多情況下,接口不太可能由結構實現,因此class
約束將是無害)。
那是因為T
不是接口IA
本身。 這是它的一個實現。
假設您有另一個實現IA
類:
Public Class B
Implements IA
Public Property B_A As String Implements IA.A
Public Property OtherProperty as Object
End Class
然后你創建一個新的Generic Class
實例,如下所示:
Dim genericObject as new GenericClass(Of B, A)
所以在這種情況下, T
現在是B
, A
不能轉換為B
在這種情況下,替換你的疑問部分,一個對我有意義的代碼:
Dim foo4 As IA = New T()
編輯由於評論
為了能夠實例化T
,有必要在類型定義中聲明New
約束。 所以泛型類聲明將是:
Public Class GenericClass(Of T As {New, IA}, T2 As A)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.