VB: Object “inaccessible due to its protection lev

2019-09-09 02:36发布

问题:

I'm having problems with this SearchButton code in VB (Visual Studio 2012):

This code in Form1.VB:

Private Sub SearchButton_Click(sender As Object, e As EventArgs) Handles SearchButton.Click 
    Dim results As Artist 
    results = Array.SearchArray(artistArray(), SearchTextBox.Text) 
End Sub 

and I'm getting an error that artistArray is inaccessible due to its protection level.

I'm new to VB, so I'm sure it's something I'm doing wrong, but I can't find it.

I have checked spelling, visibility (Public), and so on.

array.vb at the moment:

Public Class Array 
    Public artistArray() As Artist 
    Public searchResults(artistArray.Length) As Artist 
    Dim searchString As String 

    Public Function SearchArray(ByVal artistArray(), searchString) As Artist() 
        Dim x As Integer ' artist index variable for loop 
        Dim index As Integer = 0 ' index for results 
        For x = 0 To artistArray.GetUpperBound(0) 
            Dim temp As Artist = artistArray(x) 
            If temp.Name.ToLower().Contains(searchString.ToLower()) Then 
                searchResults(index) = artistArray(x) ' if search hit then add current item to result array 
                index += 1 ' and incr. result index 
            End If 
         Next 
         ReDim Preserve searchResults(index) 
         Return searchResults 
    End Function 

    ' ...
End Class

回答1:

Public is not the same as global. In fact, VB.NET doesn't even support Global variables, in the strict old VB6 sense. Even though it's Public, it's still scoped to the Array class, so you have to access if as a property of that class. However, it's also an instance property, which means it's a member of each Array object (i.e. instance), not of the class, itself, for instance:

Dim first As Artist = Array.artistArray(0)  ' Does not work

But:

Dim a As New Array()
Dim first As Artist = a.artistArray(0)  ' Works

If you want to make it a shared property, meaning it will be a member of the class, itself, rather than each instance of that class, and therefore, effectively global, you need to add the Shared keyword, like this:

Public Class Array
    Public Shared arrayArtist() As Artist
    ' ...
End Class

Then, you will be able to access it from anywhere in your project, like this:

Dim first As Artist = Array.artistArray(0)  ' Works now

Of course, having global variables is almost always a bad design decision, but that's another topic.

All of this is a bit confusing too, because you are calling your class Array. Technically, you can do that if you really want to, but I wouldn't advise it since the .NET Framework already includes a class called Array which is pretty fundamental.

Also, there's no reason to store the search results in a field of the class. It would be far better if that was scoped to be local to the search method. And it would be simpler if you used a For Each loop and a List, like this:

Public Class ArtistBusiness
    Public Shared Artists() As Artist

    Public Shared Function SearchArtists(artists() As Artist, searchString As String) As Artist()
        Dim results As New List(Of Artist)()
        For Each i As Artist In artists
            If i.Name.IndexOf(searchString, StringComparison.CurrentCultureIgnoreCase) >=0 Then
                results.Add(i)
            End If
        Next
        Return results.ToArray()
    End Function
End Class

Then, you could call it like this:

Private Sub SearchButton_Click(sender As Object, e As EventArgs) Handles SearchButton.Click 
    Dim results() As Artist 
    results = ArtistBusiness.SearchArtists(ArtistBusiness.Artists, SearchTextBox.Text) 
End Sub

It pains me to even put globals in my example, but there it is. Notice I changed the ToLower.Contains to IndexOf, since that is safer, given certain culture issues. I also changed the results variable in the click event handler to an array, since that is what the method is returning.

You can also simplify the code even more by using LINQ, like this:

Public Shared Function SearchArtists(artists() As Artist, searchString As String) As Artist()
    artists.Select(Function(x) x.Name.IndexOf(searchString, StringComparison.CurrentCultureIgnoreCase) >= 0).ToArray()
End Function

But I would advise you to spend more time learning the fundamentals before you start trying to do anything fancy, like that.



回答2:

Your whole code can be replaced by a single LINQ line

Public artists As Artist()

Public Function FindArtists(searchString As String) As Artist()
    Return artists.Where(Function(a) a.Name.ToLower().Contains(searchString)).ToArray()
End Function