Добавить вложенную перечисляемую поддержку в пользовательский класс

В настоящее время я работаю в Visual Studio 2015 с использованием Visual Basic, и у меня есть класс, который принимает строку с разделителями и может извлекать/заменять данные в позициях внутри строки, подобно зубчатому массиву, до трех уровней в глубину. Я могу расширить класс, чтобы работать с более глубокими уровнями, чем три, но пока я буду придерживаться трех. Это точно так же, как структура данных PICK mvdbms для тех, кто знаком. Базовый класс для чтения и записи данных внутри класса уже создан. Для экономии места и целесообразности я включил отредактированный код в качестве справочного материала, помогающего ответить на мой вопрос. Если нужно больше данных, я могу предоставить весь класс. Также, если в ходе обсуждения этого вопроса возникнут замечания или предложения по улучшению моего кода, я всегда готов выслушать конструктивные отзывы.

Класс:

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

Мой вопрос заключается в следующем: как мне создать перечисляемую поддержку для этого класса и ограничить ее тремя уровнями, чтобы система знала, на каком уровне она находится и какой разделитель ей нужно использовать? Например, если у меня есть следующая переменная:

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"}, второй уровень будет сначала перечислять первый элемент на верхнем уровне и возвращать {"Foo", "4", "7", "1-2", "", "6 "}, и т.д...

Есть идеи, с чего начать?

Обновлять:

Я не знаю, как включить словарь в класс, поэтому я обновил свой пост тем, что придумал раньше.

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

person Daelas Kai    schedule 03.06.2017    source источник


Ответы (2)


Я думаю, что у вас есть правильная идея с MVStringEnumerator, где вы в конечном итоге перечисляете массив строк, а не строку с разделителями MV. (Как эксперт по MVDBMS я понимаю ваши ссылки.) Это может быть довольно просто. Я бы устранил двойную обязанность этой задачи, разбор разделителей и перечисление.

Сначала сократите перечисляемый объект до самого нижнего уровня желаемого динамического массива:

myValue = myMVString.MV(1,4)

Во-вторых, сделайте это перечисляемым:

mySubValues = myValue.AsEnumerable()

Наконец, перечислите mySubValues ​​как общий массив строк. Таким образом, перечисление не знает о MV-природе исходного динамического массива. Конечно, все вышеперечисленное можно сделать более элегантно и инкапсулировать в один метод, возвращающий желаемое перечисляемое, например:

myEnumerable = myMVString.AsEnumerable(1,4)

Или, в конечном итоге, просто переберите что-то вроде new MyEnumerable(myMVSTRING(1,4)).

Обратите внимание, что если вы на самом деле работаете с MVDBMS, каждая платформа имеет свои собственные бесплатные библиотеки классов для таких вещей: MVSP, UO.NET, QMClient и т. д. Так что вам может вообще не понадобиться писать это с нуля — хотя это хорошее упражнение.

Примечание

Если вы эмулируете динамические массивы MV, ваш код использует базовый индекс 0, где MV использует 1.

person TonyG    schedule 05.06.2017
comment
Спасибо за ваш отзыв. Во-первых, я отвечу на ваше примечание. Внутри моих свойств по умолчанию я обрабатываю преобразование между позиционированием на основе 1 и позиционированием на основе 0. Что касается других ваших предложений, мне может понадобиться помощь, так как я программирую VB.NET всего 6 месяцев. Мы используем RocketD3, так что уже есть бесплатная библиотека классов; это было всего лишь учебное упражнение, которое я дал себе, чтобы расширить свое понимание VB и, вероятно, откусил больше, чем я могу проглотить. В любом случае, как мне сократить до самого низкого уровня? Я не понимаю, что вы имеете в виду. - person Daelas Kai; 05.06.2017
comment
После повторного просмотра вашего ответа, теперь я понимаю его лучше. Спасибо вам за ваши предложения. - person Daelas Kai; 08.06.2017
comment
Рад, что это имело смысл. Поищите примеры C# или VB.NET для UO.NET. Также рассмотрите возможность отправки подобных запросов на специализированные форумы U2/MVDBMS. И (хотя обычно это бесполезно) подумайте о том, чтобы запросить информацию у вашего VAR. - person TonyG; 12.06.2017

мне нравится пользоваться словарем

        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())
person jdweng    schedule 03.06.2017
comment
Я не уверен, как реализовать словарь в своем классе, поэтому я добавил то, что уже пробовал. - person Daelas Kai; 05.06.2017