簡體   English   中英

為什么我不能將類型約束的泛型參數轉換為約束類型?

[英]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) 盡管AirplaneBlueJay都是可以飛行的東西,但是人們無法將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現在是BA不能轉換為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.

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