加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

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

发布时间:2020-12-17 00:18:40 所属栏目:大数据 来源:网络整理
导读:基本问题:给定一个接口:ICopiesFrom(Of In TModel),对泛型参数没有类型约束,是否可以使用不同的类型参数在同一具体类型上多次实现该接口,而无需编译器警告? 背景信息:近年来,由于Eric Lippert先生,谷歌以及数小时的测试/实验,我对协方差和逆变的处理一直
基本问题:给定一个接口: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

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

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

Public Module Materials

    Sub Main()
        Dim materials As New List(Of Composite)()
        Dim materialData As New Dictionary(Of MaterialA,MaterialB)()

        'Load data from a data source
        'materialData = Me.DataService.Load(.....'Query parameters'.....)
        Dim specificMaterial As New SpecialB() With {.Weight = 24,.Height = 12}
        Dim specificMaterialDesc As New MaterialA() With {.Name = "Silly Putty",.Created = DateTime.UtcNow.AddDays(-1)}
        Dim basicMaterial As New MaterialB() With {.Weight = 34.2,.Height = 8}
        Dim basicMaterialDesc As New MaterialA() With {.Name = "Gak",.Created = DateTime.UtcNow.AddDays(-2)}

        materialData.Add(specificMaterialDesc,specificMaterial)
        materialData.Add(basicMaterialDesc,basicMaterial)

        For Each item In materialData
            Dim newMaterial As New Composite()

            newMaterial.CopyFrom(item.Key)
            newMaterial.CopyFrom(item.Value)
            materials.Add(newMaterial)

        Next

        Console.WriteLine("Total Weight: {0} lbs.",materials.Select(Function(x) x.Weight).Sum())
        Console.ReadLine()
    End Sub

End Module


''' <summary>
''' Class that represents a composite of two separate classes.
''' </summary>
''' <remarks></remarks>
Public Class Composite
    Implements ICopiesFrom(Of MaterialA)
    Implements ICopiesFrom(Of MaterialB)

#Region "--Constants--"

    Private Const COMPOSITE_PREFIX As String = "Comp_"

#End Region

#Region "--Instance Variables--"

    Private _created As DateTime
    Private _height As Double
    Private _name As String
    Private _weight As Double

#End Region

#Region "--Constructors--"

    ''' <summary>
    ''' Creates a new instance of the Composite class.
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub New()
        _created = DateTime.MaxValue
        _height = 1D
        _name = String.Empty
        _weight = 1D
    End Sub

#End Region

#Region "--Methods--"

    Public Overridable Overloads Sub CopyFrom(ByVal model As MaterialA) Implements ICopiesFrom(Of MaterialA).CopyFrom
        If model IsNot Nothing Then
            Me.Name = model.Name
            Me.Created = model.Created
        End If
    End Sub

    Public Overridable Overloads Sub CopyFrom(ByVal model As MaterialB) Implements ICopiesFrom(Of MaterialB).CopyFrom
        If model IsNot Nothing Then
            Me.Height = model.Height
            Me.Weight = model.Weight
        End If
    End Sub

#End Region

#Region "--Functions--"

    Protected Overridable Function GetName() As String
        Dim returnValue As String = String.Empty
        If Not String.IsNullOrWhiteSpace(Me.Name) Then
            Return String.Concat(COMPOSITE_PREFIX,Me.Name)
        End If
        Return returnValue
    End Function

#End Region

#Region "--Properties--"

    Public Overridable Property Created As DateTime
        Get
            Return _created
        End Get
        Set(value As DateTime)
            _created = value
        End Set
    End Property

    Public Overridable Property Height As Double
        Get
            Return _height
        End Get
        Set(value As Double)
            If value > 0D Then
                _height = value
            End If
        End Set
    End Property

    Public Overridable Property Name As String
        Get
            Return Me.GetName()
        End Get
        Set(value As String)
            If Not String.IsNullOrWhiteSpace(value) Then
                _name = value
            End If
        End Set
    End Property

    Public Overridable Property Weight As Double
        Get
            Return _weight
        End Get
        Set(value As Double)
            If value > 0D Then
                _weight = value
            End If
        End Set
    End Property

#End Region

End Class

''' <summary>
''' Interface that exposes a contract / defines functionality of a type whose values are derived from another type.
''' </summary>
''' <typeparam name="TModel"></typeparam>
''' <remarks></remarks>
Public Interface ICopiesFrom(Of In TModel)

#Region "--Methods--"

    ''' <summary>
    ''' Copies a given model into the current instance.
    ''' </summary>
    ''' <param name="model"></param>
    ''' <remarks></remarks>
    Sub CopyFrom(ByVal model As TModel)

#End Region

End Interface

Public Class MaterialA

#Region "--Instance Variables--"

    Private _created As DateTime
    Private _name As String

#End Region

#Region "--Constructors--"

    ''' <summary>
    ''' Creates a new instance of the MaterialA class.
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub New()
        _created = DateTime.MaxValue
        _name = String.Empty
    End Sub

#End Region

#Region "--Properties--"

    Public Overridable Property Created As DateTime
        Get
            Return _created
        End Get
        Set(value As DateTime)
            _created = value
        End Set
    End Property

    Public Overridable Property Name As String
        Get
            Return _name
        End Get
        Set(value As String)
            _name = value
        End Set
    End Property

#End Region

End Class

Public Class MaterialB

#Region "--Instance Variables--"

    Private _height As Double
    Private _weight As Double

#End Region

#Region "--Constructors--"

    ''' <summary>
    ''' Creates a new instance of the MaterialB class.
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub New()
        _height = 0D
        _weight = 0D
    End Sub

#End Region

#Region "--Properties--"

    Public Overridable Property Height As Double
        Get
            Return _height
        End Get
        Set(value As Double)
            _height = value
        End Set
    End Property

    Public Overridable Property Weight As Double
        Get
            Return _weight
        End Get
        Set(value As Double)
            _weight = value
        End Set
    End Property

#End Region

End Class

Public Class SpecialB
    Inherits MaterialB

    Public Overrides Property Weight As Double
        Get
            Return MyBase.Weight
        End Get
        Set(value As Double)
            MyBase.Weight = value * 2
        End Set
    End Property

End Class

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

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

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

Public Class Composite
Implements ICopiesFrom(Of MaterialA)
Implements ICopiesFrom(Of MaterialB)

结合

Public Interface ICopiesFrom(Of In TModel)

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

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

所以,如果我说:

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

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

接口可能更清楚的情况:

Public Class Composite2
Implements ICopiesFrom(Of IMaterialA)
Implements ICopiesFrom(Of IMaterialB)
...
Public Class Broken
Implements IMaterialA
Implements IMaterialB
...
Dim broken As ICopiesFrom(Of Broken) = New Composite()

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

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读