Search code examples
vb.netlistconstantsshared

How to create a List of constants


I have a class inside another class that has public access called SampleRating. There is a list of objects of the type of SampleRating called SampleRatings. The data stored in the list items should never be changed after it is initially set, only queried. The list itself should also never be changed.

What is the correct way of making the list and the values therein, have a read-only property? I tried Const or Static but the compiler complains about both.

My class and List:

Public Class Foo
    Public Class SampleRating
        Enum SampleRateSetting As Byte
            SR0 = 1
            SR1 = 2
            SR2 = 4
            SR3 = 8
        End Enum

        Public Setting As SampleRateSetting
        Public Noise As UInt16
        Public Bandwidth As UInt16
        Public SampleRate As UInt32
        Public BinWidth As Double

        Public Shared Function FindSetting(Setting As SampleRateSetting) As Predicate(Of SampleRating)
            Return Function(Rating As SampleRating) Rating.Setting = Setting
        End Function
    End Class

    Public Shared SampleRatings As New List(Of SampleRating) From {
       New SampleRating With {.Setting = SampleRating.SampleRateSetting.SR0, .SampleRate = 100189, .BinWidth = 196, .Bandwidth = 26000, .Noise = 467},
       New SampleRating With {.Setting = SampleRating.SampleRateSetting.SR1, .SampleRate = 12524, .BinWidth = 25, .Bandwidth = 6262, .Noise = 260},
       New SampleRating With {.Setting = SampleRating.SampleRateSetting.SR2, .SampleRate = 1566, .BinWidth = 3.1, .Bandwidth = 783, .Noise = 100},
       New SampleRating With {.Setting = SampleRating.SampleRateSetting.SR3, .SampleRate = 196, .BinWidth = 0.38, .Bandwidth = 98, .Noise = 38}
   }

   ' Have also tried the below instead, with no luck
   Public Shared SampleRatings As New ReadOnlyCollection(Of SampleRating)(New List(Of SampleRating)() From {
       New SampleRating With {.Setting = SampleRating.SampleRateSetting.SR0, .SampleRate = 100189, .BinWidth = 196, .Bandwidth = 26000, .Noise = 467},
       New SampleRating With {.Setting = SampleRating.SampleRateSetting.SR1, .SampleRate = 12524, .BinWidth = 25, .Bandwidth = 6262, .Noise = 260},
       New SampleRating With {.Setting = SampleRating.SampleRateSetting.SR2, .SampleRate = 1566, .BinWidth = 3.1, .Bandwidth = 783, .Noise = 100},
       New SampleRating With {.Setting = SampleRating.SampleRateSetting.SR3, .SampleRate = 196, .BinWidth = 0.38, .Bandwidth = 98, .Noise = 38}
    })

    Function Shared Bar() As Boolean
        ' Should NOT be able to change the list or list item members here.
    End Function
End Class 'End of Foo

Solution

  • If you want to make sure the List and the list items are both read only, you'll have to do 2 things.

    First, you'll need to use a ReadOnlyCollection instead of a list. Basically, you create your list normally using a standard List object and once it's completed, you can call the AsReadOnly method on your List to get a ReadOnlyCollection.

    The second thing you'll have to do is to create read-only properties. Depending on your needs, you may also consider adding a private setter for your property... by definition, it won't be a read-only property, but the setter won't be exposed outside your class so it will prevent any other object from changing the value of your property.

    UPDATE

    You mentioned that the property should not be modified from the Bar function... The problem here is that you're trying to prevent modifications in SampleRatings in a class that is also used to initialize the SampleRatings.

    Notice the private setter in the following example. When it's private, you can't initialize the SampleRatings, but if you make it public, you'll be able to change it in the Bar function.

    Public Class Foo
        Public Class SampleRating
            Private _noise As UInt16
            Public Property Noise() As UInt16
                Get
                    Return _noise
                End Get
                Private Set(ByVal value As UInt16)
                    _noise = value
                End Set
            End Property
        End Class
    
        'If the noise is read-only (or has a private setter), you won't be able to set the noise value here...
        Public Shared SampleRatings As New ReadOnlyCollection(Of SampleRating)(New List(Of SampleRating)() From {
            New SampleRating With {.Noise = 467},
            New SampleRating With {.Noise = 260},
            New SampleRating With {.Noise = 100},
            New SampleRating With {.Noise = 38}
         })
    
        Shared Function Bar()
    
            'Doesn't work
            SampleRatings.Remove(SampleRatings.First())
    
            'Doesn't work
            SampleRatings.First().Noise = 1
    
        End Function
    
    End Class
    

    You didn't mention why you want to prevent modification in your list in the first place... if you want to prevent modification from external assemblies, you should consider declaring your setter as Friend (see Access Levels in Visual Basic).