VB.NET实现多种Contravariant接口类型

前端之家收集整理的这篇文章主要介绍了VB.NET实现多种Contravariant接口类型前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
基本问题:给定一个接口:ICopiesFrom(Of In TModel),对泛型参数没有类型约束,是否可以使用不同的类型参数在同一具体类型上多次实现该接口,而无需编译器警告?

背景信息:近年来,由于Eric Lippert先生,谷歌以及数小时的测试/实验,我对协方差和逆变的处理一直在增加.在我正在开发的项目中,我需要分离架构的不同层,而不是将基础模型/实体类型暴露给更高层(表示).为了实现这一点,我一直在创建复合类(MVC模型),其中包含潜在的多个不同基础层模型类型的方面.我有一个单独的层,将从基本类型(服务层)构建这些复合类型.一个重要的要求是基类型不能通过引用传递,因此必须复制属性才能创建基本模型类的深层副本.

为了从服务层中删除一些冗长而丑陋的代码,我创建了一个接口,该接口定义了复合类型的通用契约,允许在复合对象中复制属性值.但是,当我想多次实现此接口时,VB编译器会生成警告.程序运行得很好,但我想了解为什么会发生这种情况的具体细节.特别是,如果这是一个脆弱或糟糕的设计决定,我想在我变得太深之前就知道了.

环境细节:

>语言:VB.Net
> .NET:4.0
> IDE:VS2010 SP1
>用法:网站(MVC2)

在试图解决这个问题时,我已经对SO和互联网做了一些研究,但没有真正解决我的问题.以下是我咨询过的一些(但不是全部)资源:

> Contravariance explained
> http://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx
> http://ericlippert.com/2013/07/29/a-contravariance-conundrum/#more-1344

简介:有没有更好/更清晰/更灵活的方式来实现我正在尝试或者我必须忍受编译器警告?

以下是说明问题的可运行示例(不是实际代码):

  1. Public Module Materials
  2.  
  3. Sub Main()
  4. Dim materials As New List(Of Composite)()
  5. Dim materialData As New Dictionary(Of MaterialA,MaterialB)()
  6.  
  7. 'Load data from a data source
  8. 'materialData = Me.DataService.Load(.....'Query parameters'.....)
  9. Dim specificMaterial As New SpecialB() With {.Weight = 24,.Height = 12}
  10. Dim specificMaterialDesc As New MaterialA() With {.Name = "Silly Putty",.Created = DateTime.UtcNow.AddDays(-1)}
  11. Dim basicMaterial As New MaterialB() With {.Weight = 34.2,.Height = 8}
  12. Dim basicMaterialDesc As New MaterialA() With {.Name = "Gak",.Created = DateTime.UtcNow.AddDays(-2)}
  13.  
  14. materialData.Add(specificMaterialDesc,specificMaterial)
  15. materialData.Add(basicMaterialDesc,basicMaterial)
  16.  
  17. For Each item In materialData
  18. Dim newMaterial As New Composite()
  19.  
  20. newMaterial.CopyFrom(item.Key)
  21. newMaterial.CopyFrom(item.Value)
  22. materials.Add(newMaterial)
  23.  
  24. Next
  25.  
  26. Console.WriteLine("Total Weight: {0} lbs.",materials.Select(Function(x) x.Weight).Sum())
  27. Console.ReadLine()
  28. End Sub
  29.  
  30. End Module
  31.  
  32.  
  33. ''' <summary>
  34. ''' Class that represents a composite of two separate classes.
  35. ''' </summary>
  36. ''' <remarks></remarks>
  37. Public Class Composite
  38. Implements ICopiesFrom(Of MaterialA)
  39. Implements ICopiesFrom(Of MaterialB)
  40.  
  41. #Region "--Constants--"
  42.  
  43. Private Const COMPOSITE_PREFIX As String = "Comp_"
  44.  
  45. #End Region
  46.  
  47. #Region "--Instance Variables--"
  48.  
  49. Private _created As DateTime
  50. Private _height As Double
  51. Private _name As String
  52. Private _weight As Double
  53.  
  54. #End Region
  55.  
  56. #Region "--Constructors--"
  57.  
  58. ''' <summary>
  59. ''' Creates a new instance of the Composite class.
  60. ''' </summary>
  61. ''' <remarks></remarks>
  62. Public Sub New()
  63. _created = DateTime.MaxValue
  64. _height = 1D
  65. _name = String.Empty
  66. _weight = 1D
  67. End Sub
  68.  
  69. #End Region
  70.  
  71. #Region "--Methods--"
  72.  
  73. Public Overridable Overloads Sub CopyFrom(ByVal model As MaterialA) Implements ICopiesFrom(Of MaterialA).CopyFrom
  74. If model IsNot Nothing Then
  75. Me.Name = model.Name
  76. Me.Created = model.Created
  77. End If
  78. End Sub
  79.  
  80. Public Overridable Overloads Sub CopyFrom(ByVal model As MaterialB) Implements ICopiesFrom(Of MaterialB).CopyFrom
  81. If model IsNot Nothing Then
  82. Me.Height = model.Height
  83. Me.Weight = model.Weight
  84. End If
  85. End Sub
  86.  
  87. #End Region
  88.  
  89. #Region "--Functions--"
  90.  
  91. Protected Overridable Function GetName() As String
  92. Dim returnValue As String = String.Empty
  93. If Not String.IsNullOrWhiteSpace(Me.Name) Then
  94. Return String.Concat(COMPOSITE_PREFIX,Me.Name)
  95. End If
  96. Return returnValue
  97. End Function
  98.  
  99. #End Region
  100.  
  101. #Region "--Properties--"
  102.  
  103. Public Overridable Property Created As DateTime
  104. Get
  105. Return _created
  106. End Get
  107. Set(value As DateTime)
  108. _created = value
  109. End Set
  110. End Property
  111.  
  112. Public Overridable Property Height As Double
  113. Get
  114. Return _height
  115. End Get
  116. Set(value As Double)
  117. If value > 0D Then
  118. _height = value
  119. End If
  120. End Set
  121. End Property
  122.  
  123. Public Overridable Property Name As String
  124. Get
  125. Return Me.GetName()
  126. End Get
  127. Set(value As String)
  128. If Not String.IsNullOrWhiteSpace(value) Then
  129. _name = value
  130. End If
  131. End Set
  132. End Property
  133.  
  134. Public Overridable Property Weight As Double
  135. Get
  136. Return _weight
  137. End Get
  138. Set(value As Double)
  139. If value > 0D Then
  140. _weight = value
  141. End If
  142. End Set
  143. End Property
  144.  
  145. #End Region
  146.  
  147. End Class
  148.  
  149. ''' <summary>
  150. ''' Interface that exposes a contract / defines functionality of a type whose values are derived from another type.
  151. ''' </summary>
  152. ''' <typeparam name="TModel"></typeparam>
  153. ''' <remarks></remarks>
  154. Public Interface ICopiesFrom(Of In TModel)
  155.  
  156. #Region "--Methods--"
  157.  
  158. ''' <summary>
  159. ''' Copies a given model into the current instance.
  160. ''' </summary>
  161. ''' <param name="model"></param>
  162. ''' <remarks></remarks>
  163. Sub CopyFrom(ByVal model As TModel)
  164.  
  165. #End Region
  166.  
  167. End Interface
  168.  
  169. Public Class MaterialA
  170.  
  171. #Region "--Instance Variables--"
  172.  
  173. Private _created As DateTime
  174. Private _name As String
  175.  
  176. #End Region
  177.  
  178. #Region "--Constructors--"
  179.  
  180. ''' <summary>
  181. ''' Creates a new instance of the MaterialA class.
  182. ''' </summary>
  183. ''' <remarks></remarks>
  184. Public Sub New()
  185. _created = DateTime.MaxValue
  186. _name = String.Empty
  187. End Sub
  188.  
  189. #End Region
  190.  
  191. #Region "--Properties--"
  192.  
  193. Public Overridable Property Created As DateTime
  194. Get
  195. Return _created
  196. End Get
  197. Set(value As DateTime)
  198. _created = value
  199. End Set
  200. End Property
  201.  
  202. Public Overridable Property Name As String
  203. Get
  204. Return _name
  205. End Get
  206. Set(value As String)
  207. _name = value
  208. End Set
  209. End Property
  210.  
  211. #End Region
  212.  
  213. End Class
  214.  
  215. Public Class MaterialB
  216.  
  217. #Region "--Instance Variables--"
  218.  
  219. Private _height As Double
  220. Private _weight As Double
  221.  
  222. #End Region
  223.  
  224. #Region "--Constructors--"
  225.  
  226. ''' <summary>
  227. ''' Creates a new instance of the MaterialB class.
  228. ''' </summary>
  229. ''' <remarks></remarks>
  230. Public Sub New()
  231. _height = 0D
  232. _weight = 0D
  233. End Sub
  234.  
  235. #End Region
  236.  
  237. #Region "--Properties--"
  238.  
  239. Public Overridable Property Height As Double
  240. Get
  241. Return _height
  242. End Get
  243. Set(value As Double)
  244. _height = value
  245. End Set
  246. End Property
  247.  
  248. Public Overridable Property Weight As Double
  249. Get
  250. Return _weight
  251. End Get
  252. Set(value As Double)
  253. _weight = value
  254. End Set
  255. End Property
  256.  
  257. #End Region
  258.  
  259. End Class
  260.  
  261. Public Class SpecialB
  262. Inherits MaterialB
  263.  
  264. Public Overrides Property Weight As Double
  265. Get
  266. Return MyBase.Weight
  267. End Get
  268. Set(value As Double)
  269. MyBase.Weight = value * 2
  270. End Set
  271. End Property
  272.  
  273. End Class

The program runs just fine,but I want to understanding the specifics
of why this is happening

因为(接口)和/或具有预先存在的继承层次结构的类的(通用)逆变而存在警告.它没有特别适用于您在示例中给出的情况(可能在您的实际代码中),但这就是它警告的原因:

假设MaterialB继承了MaterialA,然后由SpecialB继承

  1. Public Class Composite
  2. Implements ICopiesFrom(Of MaterialA)
  3. Implements ICopiesFrom(Of MaterialB)

结合

  1. Public Interface ICopiesFrom(Of In TModel)

说(由于’In’):
Composite可以是ICopiesFrom(Of<任何继承自MaterialA的东西>)(有一个实现)

Composite可以是ICopiesFrom(Of<任何继承自MaterialB的东西>)(第二个实现)

所以,如果我说:

  1. Dim broken As ICopiesFrom(Of SpecialB) = New Composite()

它应该选择哪种实现,两者都是有效的(选择B似乎很自然,但它是模棱两可的)

接口可能更清楚的情况:

  1. Public Class Composite2
  2. Implements ICopiesFrom(Of IMaterialA)
  3. Implements ICopiesFrom(Of IMaterialB)
  4. ...
  5. Public Class Broken
  6. Implements IMaterialA
  7. Implements IMaterialB
  8. ...
  9. Dim broken As ICopiesFrom(Of Broken) = New Composite()

编译器现在应该使用哪种实现?

此外,您的示例中没有任何内容需要In关键字(可能在实际代码中可能存在).除非你需要’传递’复合AS作为ICopiesFrom(Of SpecialB),例如你什么都没有,ICopiesFrom(Of MaterialB)可以通过普通(非通用)机制处理没有(通用)逆变的SpecialB.

猜你在找的VB相关文章