繁体   English   中英

测试该通用类型实现一个接口并使用该接口

[英]Testing that generic type implements an interface and using that interface

我正在构建一个使用物理性能测量的应用程序。 最初,我使用了一堆类型为'double'的变量,并以匈牙利表示法或头脑中的方式跟踪值:

Public Class ResultData
    Public Property position_in_mm_vs_time_in_ms as Double(,)
    Public Property initial_position_in_mm as Double
    Public Property final_position_in_mm as Double
    Public Property duration_in_ms as Double
    Public Property speed_in_mm_per_s as Double
End Class

但是随着我添加更多的项目和更多的属性,很快就陷入了混乱,转换因子泛滥,无法知道某个值是以米还是毫安为单位,也无法知道没有硬编码的情况下该项目的正确缩写是什么和手动跟踪,以及在SI或Imperial单位中添加用于输入和输出数据的选项的想法令人恐惧。

我意识到这个问题是打字问题,我可以使用带有类型和值的类来改善这种安排:

Namespace Measure
    Public Class Value(Of GenericUnits)
        Public Property Value As Double
    End Class
    Public Class ValuePoint(Of XUnits, YUnits)
        Public X As Value(Of XUnits)
        Public Y As Value(Of YUnits)
        Public Sub New(x As Value(Of XUnits), y As Value(Of YUnits))
            Me.X = x
            Me.Y = y
        End Sub
    End Class
    Public Class Units
        Public Interface GenericUnits
            ReadOnly Property Abbreviation As String
            ' Additional properties, operators, and conversion functions
        End Interface
        ' Additional unit types
    End Class
End Namespace

所以我的声明变成了:

Public Class ResultData
    Public Property PositionData as List(of ValuePoint(of Units.Seconds, Units.Millimeters))
    Public Property InitialPosition as Value(of Units.Millimeters)
    Public Property FinalPosition as Value(of Units.Millimeters)
    Public Property Duration as Value(of Units.Milliseconds)
    Public Property Speed as Value(of Units.MillimetersPerSecond)
End Class

这真的很干净。 现在,我想使用操作员定义的属性和转换,但不能:

Dim result As New ResultData()
Dim msg As New System.Text.StringBuilder()
msg.AppendLine("Speed units are abbreviated as: ")
msg.AppendLine(result.Speed.GetType().ToString() & "?")
msg.AppendLine(result.Speed.GetType().GenericTypeArguments(0).ToString() & "?")
' Produces error "Abbreviation is not a member of System.Type"
' Casting produces conversion error
'msg.AppendLine(result.Speed.GetType().GenericTypeArguments(0).Abbreviation & "?")
' Produces:
'   Speed units are abbreviated as:
'   Measure.Value`1[Measure.Units+MillimetersPerSecond]
'   Measure.Units+MillimetersPerSecond
MsgBox(msg.ToString())

如何访问类型声明的属性和方法?

我发现我的声明Value(Of GenericUnits)实际上没有引用名为GenericUnits的接口,而是生成了一个泛型类型。 我不妨称之为Value(Of T) 我认为这可能与我的问题有关。

您需要限制泛型从接口派生:

Public Class Measurement(Of T as IGenericUnits) 'class name was Value before edit 
    Public Property Value As Double
    Public Property UOM As IGenericUnits 'UOM is a common abbreviation for unit-of-measure
End Class

有关泛型和约束的其他信息,请参见此处: http : //msdn.microsoft.com/zh-cn/library/w256ka79.aspx


编辑:

用法如下:

msg.AppendLine(result.Speed.UOM.Abbreviation)

一些建议:

  1. GenericUnits重命名为IGenericUnits以遵循建议的命名约定

  2. Value" for your measurement class.找到一个比“ Value" for your measurement class.更好的名称is used all over the place and you are bound to run into a naming conflict eventually. Perhaps Measurement or MeasuredValue`。

我通常会在这里跳过泛型。 要做的全部工作是为每个单位创建类型安全的容器:毫米,毫安等。您希望在期望毫安的计算中不能使用毫米。 如果您具有通用值的集合,则此错误仍然可能发生。

我要做的仍然是为您的度量定义一个通用接口。 但是包含Value应该是接口的一部分。 我仍然会为毫安和毫米等实现特定的类型。 这些类型也可能内置了隐式或显式转换。但是,我将使用.Net中已包含的现有通用集合和类型,而不是构建任何新的集合和类型。 更重要的是,在使用类型时,我会要求最终的具体类型并实现接口,而避免要求接口本身:

Public Interface IUnit
    ReadOnly Property Abbreviation As String
    Property Value As Double
End Interface

Public Class MilliAmps Implements IUnit
    Public ReadOnly Property Abbreviation As String Implements IUnit.Abbreviation
        Get
          Return "ma"
        End Get
    End Property

    Public Property Value As Double Implements IUnit.Value
End Class

Public Class Millimeters Implements IUnit
    Public ReadOnly Property Abbreviation As String Implements IUnit.Abbreviation
        Get
          Return "mm"
        End Get
    End Property

    Public Property Value As Double Implements IUnit.Value
End Class
Public Class Seconds ...
Public Class MillimetersPerSecond ...

Public Class ResultData
    Public Property PositionData As List(Of Tuple(Of Seconds, Millimeters))
    Public Property InitialPosition As Millimeters
    Public Property FinalPosition As Millimeters
    Public Property Duration As Milliseconds
    Public Property Speed As MillimetersPerSecond
End Class

我什至会尝试使用完整的抽象基类,而不是使用接口,因为这将使我避免一遍又一遍地重新实现相同的value属性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM