vb.net – 为什么我不能将类型约束的泛型参数转换为约束类型?

我习惯于使用接口,泛型并在真实环境中使用继承来开发它们,同时尝试使用并将其实现为我们即将开展的项目之一的新架构,并且我对于我对此感到困惑的泛型有疑问.

这对我自己来说更像是一个教育问题,因为我无法理解为什么.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作为IA,为什么在add方法中是Dim foo4因为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)

以上都是?这对于我来说已经成为一个学习曲线,但是我对于为什么我在逻辑上无法做到这一点感到非常困惑?

编辑:抱歉忘记了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语言将隐式地将前一种类型转换为后者,并允许代码将后者明确地转换为前者.接口类型存储位置只能保存对堆对象的引用.这很重要,因为它意味着虽然实现接口的结构可以转换为该接口类型,但这并不意味着结构的实例是该接口类型的实例.协方差的前提是每个对象都由例如IEnumerable< DerivedType>可以直接用作BaseType的实例而无需转换.这种直接替代性适用于继承的类类型,以及由类类型实现的接口.它不适用于结构类型实现的接口,也不适用于没有类约束的泛型.将类约束添加到泛型类类型参数将允许该类型参数参与协方差,但可能排除使用结构作为泛型类型参数.注意,除非有特别的理由期望接口将由结构实现(例如IComparable< T>的情况),在许多情况下,接口不可能由结构实现,因此类约束将是无害的).

转载注明原文:vb.net – 为什么我不能将类型约束的泛型参数转换为约束类型? - 代码日志