5

VB.NET プロジェクトに、プロパティを持つパブリック クラスがありList(Of String)ます。このリストはプロジェクト内の他のクラスによって変更される必要がありますが、クラスは (将来のある時点で) プロジェクトの外部に公開される可能性があるため、そのレベルで変更できないようにしたいと考えています。プロジェクト内の既存のプロパティの変更は、リストのメソッドを呼び出すことによってのみ行われます (特に.Add、場合.Clearによっては )。プロパティ値を新しいリストに大規模に置き換えることではありません (そのため、ReadOnlyプロパティとして持っています)。

私はそれを行う方法を思いつきましたが、それがまさにあなたが「エレガント」と呼ぶものかどうかはわかりません.

それはこれです:

Friend mlst_ParameterNames As List(Of String) = New List(Of String)

Public ReadOnly Property ParameterNames() As List(Of String)
    Get
        Return New List(Of String)(mlst_ParameterNames)
    End Get
End Property

これで問題なく動作します。フィールドに直接アクセスするプロジェクト内の任意のクラスは、mlst_ParameterNames必要に応じてフィールドを変更できますが、パブリック プロパティを介してフィールドにアクセスするプロシージャは、思いのままに変更できますが、プロパティ プロシージャは常にコピーを返すため、どこにも到達しません。リスト自体ではなく、リストの。

しかし、もちろん、それにはオーバーヘッドがかかるため、機能していても、あるレベルで内臓的に「間違っている」と感じています。

パラメータ リストが巨大になることはありません。多くても 50 個のアイテムしか含まれませんが、より一般的には 10 個未満のアイテムしか含まれないため、これがパフォーマンス キラーになることはないと思います。しかし、もちろん、VB.NET の使用時間をはるかに長くしている誰かが、もっときちんとした、よりクリーンなアイデアを持っているのではないかと考えるようになりました。

誰?

4

2 に答える 2

1

Locked設定できるプロパティを提供すると、他の各プロパティがこれをチェックして、ロックされているかどうかを確認します...

Private m_Locked As Boolean = False
Private mlst_ParameterNames As List(Of String) = New List(Of String)

Public Property ParameterNames() As List(Of String)
    Get
        Return New List(Of String)(mlst_ParameterNames)
    End Get
    Set(value As List(Of String))
        If Not Locked Then
            mlst_ParameterNames = value
        Else
            'Whatever action you like here...
        End If
    End Set
End Property

Public Property Locked() As Boolean
    Get
        Return m_Locked
    End Get
    Set(value As Boolean)
        m_Locked = value
    End Set
End Property

- 編集 -

これに追加するだけで、ここに基本的なコレクションがあります...

''' <summary>
''' Provides a convenient collection base for search fields.
''' </summary>
''' <remarks></remarks>
Public Class SearchFieldList
        Implements ICollection(Of String)

#Region "Fields..."

        Private _Items() As String
        Private _Chunk As Int32 = 16
        Private _Locked As Boolean = False
        'I've added this in so you can decide if you want to fail on an attempted set or not...
        Private _ExceptionOnSet As Boolean = False

        Private ptr As Int32 = -1
        Private cur As Int32 = -1

#End Region
#Region "Properties..."

        Public Property Items(ByVal index As Int32) As String
            Get
                'Make sure we're within the index bounds...
                If index < 0 OrElse index > ptr Then
                    Throw New IndexOutOfRangeException("Values between 0 and " & ptr & ".")
                Else
                    Return _Items(index)
                End If
            End Get
            Set(ByVal value As String)
                'Make sure we're within the index bounds...
                If index >= 0 AndAlso Not _Locked AndAlso index <= ptr Then
                    _Items(index) = value
                ElseIf _ExceptionOnSet Then
                    Throw New IndexOutOfRangeException("Values between 0 and " & ptr & ". Use Add() or AddRange() method to append fields to the collection.")
                End If
            End Set
        End Property

        Friend Property ChunkSize() As Int32
            Get
                Return _Chunk
            End Get
            Set(ByVal value As Int32)
                _Chunk = value
            End Set
        End Property

        Public ReadOnly Property Count() As Integer Implements System.Collections.Generic.ICollection(Of String).Count
            Get
                Return ptr + 1
            End Get
        End Property
        ''' <summary>
        ''' Technically unnecessary, just kept to provide coverage for ICollection interface.
        ''' </summary>
        ''' <returns>Always returns false</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property IsReadOnly() As Boolean Implements System.Collections.Generic.ICollection(Of String).IsReadOnly
            Get
                Return False
            End Get
        End Property

#End Region
#Region "Methods..."

        Public Shadows Sub Add(ByVal pItem As String) Implements System.Collections.Generic.ICollection(Of String).Add
            If Not _Items Is Nothing AndAlso _Items.Contains(pItem) Then Throw New InvalidOperationException("Field already exists.")
            ptr += 1
            If Not _Items Is Nothing AndAlso ptr > _Items.GetUpperBound(0) Then SetSize()
            _Items(ptr) = pItem
        End Sub

        Public Shadows Sub AddRange(ByVal collection As IEnumerable(Of String))
            Dim cc As Int32 = collection.Count - 1
            For sf As Int32 = 0 To cc
                If _Items.Contains(collection.ElementAt(sf)) Then
                    Throw New InvalidOperationException("Field already exists [" & collection.ElementAt(sf) & "]")
                Else
                    Add(collection.ElementAt(sf))
                End If
            Next
        End Sub

        Public Function Remove(ByVal item As String) As Boolean Implements System.Collections.Generic.ICollection(Of String).Remove
            Dim ic As Int32 = Array.IndexOf(_Items, item)
            For lc As Int32 = ic To ptr - 1
                _Items(lc) = _Items(lc + 1)
            Next lc
            ptr -= 1
        End Function

        Public Sub Clear() Implements System.Collections.Generic.ICollection(Of String).Clear
            ptr = -1
        End Sub

        Public Function Contains(ByVal item As String) As Boolean Implements System.Collections.Generic.ICollection(Of String).Contains
            Return _Items.Contains(item)
        End Function

        Public Sub CopyTo(ByVal array() As String, ByVal arrayIndex As Integer) Implements System.Collections.Generic.ICollection(Of String).CopyTo
            _Items.CopyTo(array, arrayIndex)
        End Sub

#End Region
#Region "Private..."

        Private Sub SetSize()
            If ptr = -1 Then
                ReDim _Items(_Chunk)
            Else
                ReDim Preserve _Items(_Items.GetUpperBound(0) + _Chunk)
            End If
        End Sub

        Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of String) Implements System.Collections.Generic.IEnumerable(Of String).GetEnumerator
            Return New GenericEnumerator(Of String)(_Items, ptr)
        End Function

        Private Function GetEnumerator1() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
            Return GetEnumerator()
        End Function

#End Region

End Class

Friend Class GenericEnumerator(Of T)
        Implements IEnumerator(Of T)

#Region "fields..."

        Dim flist() As T
        Dim ptr As Int32 = -1
        Dim size As Int32 = -1

#End Region
#Region "Properties..."

        Public ReadOnly Property Current() As T Implements System.Collections.Generic.IEnumerator(Of T).Current
            Get
                If ptr > -1 AndAlso ptr < size Then
                    Return flist(ptr)
                Else
                    Throw New IndexOutOfRangeException("=" & ptr.ToString())
                End If
            End Get
        End Property

        Public ReadOnly Property Current1() As Object Implements System.Collections.IEnumerator.Current
            Get
                Return Current
            End Get
        End Property

#End Region
#Region "Constructors..."


        Public Sub New(ByVal fieldList() As T, Optional ByVal top As Int32 = -1)
            flist = fieldList
            If top = -1 Then
                size = fieldList.GetUpperBound(0)
            ElseIf top > -1 Then
                size = top
            Else
                Throw New ArgumentOutOfRangeException("Expected integer 0 or above.")
            End If
        End Sub

#End Region
#Region "Methods..."

        Public Function MoveNext() As Boolean Implements System.Collections.IEnumerator.MoveNext
            ptr += 1
            Return ptr <= size
        End Function

        Public Sub Reset() Implements System.Collections.IEnumerator.Reset
            ptr = -1
        End Sub

        Public Sub Dispose() Implements IDisposable.Dispose
            GC.SuppressFinalize(Me)
        End Sub

#End Region

End Class
于 2013-06-05T09:07:10.630 に答える