为自定义添加嵌套可枚举支持 class

Add nested enumerable support to custom class

我目前在 Visual Studio 2015 年使用 Visual Basic 工作,我有一个 class 接受分隔字符串并且可以 extract/replace 字符串中的位置数据,类似于锯齿状的阵法,深达三层。我可能会扩展 class 以处理比三个级别更深的级别,但现在,我将坚持使用三个级别。对于那些熟悉的人来说,这就像一个 PICK mvdbms 数据结构。在 class 中读取和写入数据的基础 class 已经构建。为了 space 和权宜之计,我将经过编辑的代码作为参考来帮助解决我的问题。如果需要更多数据,我可以提供整个class。另外,如果在讨论这个问题的过程中有改进我的代码的疑虑或建议,我总是愿意听取建设性的反馈。

class:

Public Class MVString

#Region " Properties "
    Private Record As String
    Default WriteOnly Property MV(ByVal str As String) As MVString
        Set
            Record = str
        End Set
    End Property

    Default Public Property MV(ByVal AMPos As Integer) As MVString
       'Get and set value at top level
    End Property

    Default Public Property MV(ByVal AMPos As Integer, ByVal VMPos As Integer) As MVString
        'Get and set value at middle level
    End Property

    Default Public Property MV(ByVal AMPos As Integer, ByVal VMPos As Integer, ByVal SMPos As Integer) As MVString
        'Get and set value at deepest level
    End Property
#End Region

#Region " Constructors "
    Public Sub New()
        Record = ""
    End Sub

    Public Sub New(ByVal str As String)
        Record = str
    End Sub
#End Region

#Region " Methods "
    Public Sub Clear()
        Record = ""
    End Sub

    Public Overrides Function ToString() As String
        Return Record
    End Function
#End Region

#Region " Operators "
    Public Shared Widening Operator CType(v As String) As MVString
        Return New MVString(v)
    End Operator

    Public Shared Widening Operator CType(v As MVString) As String
        Return v.ToString
    End Operator
#End Region

End Class

我的问题是:如何为此 class 创建可枚举支持并将其限制为三个级别,以便系统知道它在哪个级别以及需要使用哪个分隔符?例如,如果我有以下变量:

Dim DelimitedString As String = "Foo,4,7,1-2,,6|Bar,4,2,8-7,5,7|Fly,4,,8-7,5,7"

顶层的分隔符是“|”,第二层的分隔符是“,”,最深层的分隔符是“-”。在这种情况下,顶层将是一个数组{"Foo,4,7,1-2,,6","Bar,4,2,8-7,5,7","Fly,4,,8-7,5,7"},第二层将首先枚举上层的第一个元素,然后return {"Foo"、“4”、“7”、“1-2”、“”、“6”}等...

关于从哪里开始的任何想法?

更新:

我不确定如何将字典合并到 class 中,所以我用我之前想出的内容更新了我的 post。

Public Function GetEnumerator() As IEnumerator(Of String) Implements IEnumerable(Of String).GetEnumerator
    Return New MVStringEnumerator(Record)
End Function

Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
    Return Me.GetEnumerator()
End Function

Private Class MVStringEnumerator
    Implements IEnumerator(Of String)

    Private _ThisArray() As String
    Private idx As Integer

    Public ReadOnly Property Current As String Implements IEnumerator(Of String).Current
        Get
            Return If(idx < _ThisArray.Count, _ThisArray(idx), DirectCast(Nothing, String))
        End Get
    End Property

    Private ReadOnly Property IEnumerator_Current As Object Implements IEnumerator.Current
        Get
            Return Me.Current
        End Get
    End Property

    Public Sub New(ByVal record As String)
        Select Case True
            Case record.Contains("|"c)
                _ThisArray = Split(record, "|"c)
            Case record.Contains(","c)
                _ThisArray = Split(record, ","c)
            Case record.Contains("-"c)
                _ThisArray = Split(record, "-"c)
        End Select
        idx = -1
    End Sub

    Public Sub Reset() Implements IEnumerator.Reset
        idx = -1
    End Sub

    Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
        idx += 1
        If idx >= _ThisArray.Count Then Return False
        Return True
    End Function

End Class

我喜欢用字典

        Dim input As String = "Foo,4,7,1-2,,6|Bar,4,2,8-7,5,7|Fly,4,,8-7,5,7"

        Dim dict As Dictionary(Of String, String()) = input.Split("|").Select(Function(x) x.Split(",")) _
           .GroupBy(Function(x) x(0), Function(y) y.Skip(1).ToArray()) _
           .ToDictionary(Function(x) x.Key, Function(y) y.FirstOrDefault())

我认为您对 MVStringEnumerator 的想法是正确的,您最终枚举的是字符串数组而不是 MV 分隔字符串。 (作为 MVDBMS 专家,我了解您的参考资料。)这可能相当简单。我将消除此任务的双重职责,解析定界符和枚举。

首先将枚举对象削减到所需动态数组的最低级别:

myValue = myMVString.MV(1,4)

其次,使其可枚举:

mySubValues = myValue.AsEnumerable()

最后,将mySubValues枚举为一个普通的字符串数组。所以枚举不知道原始动态数组的 MV 性质。 当然,以上所有内容都可以更优雅地完成,并封装到一个 returns 所需可枚举的方法中,例如:

myEnumerable = myMVString.AsEnumerable(1,4)

或者最终只是迭代 new MyEnumerable(myMVSTRING(1,4)).

请注意,如果您实际使用的是 MVDBMS,每个平台都有自己的免费 class 库来执行此类操作:MVSP、UO.NET、QMClient 等。所以您可能根本不需要从头开始编写 - 虽然这是一个很好的练习。

旁注

如果您正在模拟 MV 动态数组,您的代码使用基本索引 0,而 MV 使用 1。