VB.Net错误检查列表中的字典是否包含字符串

时间:2019-02-20 07:23:54

标签: vb.net dictionary

我正在创建一个应用程序,在该应用程序中,字典中存储了不同的库,书籍和非书籍媒体,并在列表框中显示了它们。用户可以为这些元素中的任何一个添加和删除其他字典。

我有一个“当前库中的书籍”和“当前库中的非书籍媒体”的列表框,它们将显示链接到该列表框中突出显示的特定库的媒体。并且用户可以自由地在库中添加和删除其他媒体。

我遇到一个问题,如果我尝试将书籍添加到当前的EquippedLibrary中,则在添加重复书籍时会出错。

两种形式的屏幕截图:

frmManager:https://prnt.sc/mnd8qf

frmAssociationScreen:https://prnt.sc/mnd8sh

整个代码:https://pastebin.com/5yHTuTXU

我尝试使用以下Sub,但是.Contains关键字由于无法从整数转换为字符串而无法工作

Private Sub btnAddBook_Click(sender As Object, e As EventArgs) Handles btnAddBook.Click
        If frmManager.EquippedLibrary(lstAllLibraries.SelectedIndex).strLibraryName.Contains(lstBookCurrLib.SelectedIndex) Then
         'Do nothing
        Else
        frmManager.EquippedLibrary(lstAllLibraries.SelectedIndex).dicBooks.Add(frmManager.Books.Keys(lstAllBooks.SelectedIndex), frmManager.Books.Values(lstAllBooks.SelectedIndex))
            lstBookCurrLib.Items.Add(lstAllBooks.SelectedItem)
        End If
    End Sub

frmAssociationScreen

Public Class frmAssociationScreen

    Private Sub frmAssociationScreen_Load(sender As Object, e As EventArgs) Handles Me.Load

        lstAllLibraries.Items.Clear()

        For Each library In frmManager.Libraries
            lstAllLibraries.Items.Add(library.Value & " --- " & library.Key)
        Next

        For Each book In frmManager.Books
            lstAllBooks.Items.Add(book.Value & " --- " & book.Key)
        Next

        For Each nonBook In frmManager.nonBookMedia
            lstAllMedia.Items.Add(nonBook.Value & " --- " & nonBook.Key)
        Next

        ' construct equipped library and define the library names
        frmManager.EquippedLibrary = New List(Of frmManager.LibraryWithMedia)

    populateEquippedLibNames()

End Sub



Sub populateEquippedLibNames()

        Dim counter As Integer
        Dim tmpSingleLib As frmManager.LibraryWithMedia

        For counter = 0 To frmManager.Libraries.Count - 1
            tmpSingleLib = New frmManager.LibraryWithMedia(frmManager.Libraries.Values(counter))
            frmManager.EquippedLibrary.Add(tmpSingleLib)
            tmpSingleLib = Nothing
        Next

    End Sub

Private Sub btnAddBook_Click(sender As Object, e As EventArgs) Handles btnAddBook.Click
    If frmManager.EquippedLibrary(lstAllLibraries.SelectedIndex).strLibraryName.Contains(lstBookCurrLib.SelectedIndex) Then
        'Do nothing
    Else
            'If lstBookCurrLib.Contains(frmManager.EquippedLibrary(lstAllLibraries.SelectedIndex).dicBooks.Add(frmManager.Books.Keys(lstAllBooks.SelectedIndex), frmManager.Books.Values(lstAllBooks.SelectedIndex))) Then
            frmManager.EquippedLibrary(lstAllLibraries.SelectedIndex).dicBooks.Add(frmManager.Books.Keys(lstAllBooks.SelectedIndex), frmManager.Books.Values(lstAllBooks.SelectedIndex))
            lstBookCurrLib.Items.Add(lstAllBooks.SelectedItem)
    End If
End Sub

        Private Sub btnRemoveBook_Click(sender As Object, e As EventArgs) Handles btnRemoveBook.Click
            frmManager.EquippedLibrary(lstAllLibraries.SelectedIndex).dicBooks.Remove(frmManager.Books.Keys(lstAllBooks.SelectedIndex))
            lstBookCurrLib.Items.Remove(lstBookCurrLib.SelectedItem)
        End Sub

        Private Sub lstAllLibraries_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstAllLibraries.SelectedIndexChanged

            lstBookCurrLib.Items.Clear()
            lstMediaCurrLib.Items.Clear()

            If frmManager.EquippedLibrary(lstAllLibraries.SelectedIndex).dicBooks.Count > 0 Then
                For counter = 0 To frmManager.EquippedLibrary(lstAllLibraries.SelectedIndex).dicBooks.Count - 1
                    lstBookCurrLib.Items.Add(frmManager.EquippedLibrary(lstAllLibraries.SelectedIndex).dicBooks.Values(counter) & " --- " & frmManager.EquippedLibrary(lstAllLibraries.SelectedIndex).dicBooks.Keys(counter))
                Next
            End If

            If frmManager.EquippedLibrary(lstAllLibraries.SelectedIndex).nonBookMedia.Count > 0 Then
                For counter = 0 To frmManager.EquippedLibrary(lstAllLibraries.SelectedIndex).nonBookMedia.Count - 1
                    lstMediaCurrLib.Items.Add(frmManager.EquippedLibrary(lstAllLibraries.SelectedIndex).nonBookMedia.Values(counter) & " --- " & frmManager.EquippedLibrary(lstAllLibraries.SelectedIndex).nonBookMedia.Keys(counter))
                Next
            End If

    End Sub

    Private Sub frmAssociationScreen_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
        frmManager.Close()
    End Sub

End Class

frmManager

Public Class frmManager

    Public Libraries As New Dictionary(Of String, String)
    Public Books As New Dictionary(Of String, String)
    Public nonBookMedia As New Dictionary(Of String, String)

    Public EquippedLibrary As New List(Of LibraryWithMedia)

    Structure LibraryWithMedia

        Dim strLibraryName As String
        Dim dicBooks As Dictionary(Of String, String)
        Dim nonBookMedia As Dictionary(Of String, String)

        Sub New(ByVal LibName As String)

            strLibraryName = LibName
            dicBooks = New Dictionary(Of String, String)
            nonBookMedia = New Dictionary(Of String, String)

        End Sub

    End Structure

    Private Sub frmManager_Load(sender As Object, e As EventArgs) Handles Me.Load

        Libraries.Add("SVSU", "Zahnow Library")
        Libraries.Add("BR", "Fleschner Memorial Library")
        Libraries.Add("SDJ", "Scott D. James Technical Repository")

        Books.Add("104", "Data Structures for Fun and Profit")
        Books.Add("103", "Doing More With Less - Naval Lint Art")
        Books.Add("102", "Interpretive Klingon Poetry")
        Books.Add("105", "Programming with the Bidgoli")
        Books.Add("101", "Zen and the Art of Appliance Wiring")

        nonBookMedia.Add("201", "CD - IEEE Computer: the Hits")
        nonBookMedia.Add("203", "DVD - Databases and You: the Video Experience")
        nonBookMedia.Add("202", "DVD - The Pirates of Silicon Valley")

        populatelstLibrary()
        populatelstBooks()
        populatelstBookMedia()

    End Sub

    Sub populatelstLibrary()

        lstLibraries.Items.Clear()

        For Each library In Libraries
            lstLibraries.Items.Add(library.Value & " --- " & library.Key)
        Next

    End Sub

1 个答案:

答案 0 :(得分:3)

在当前状态下,您的代码相当混乱,因为它包含很多重复/相似的部分以及一些很长的行。通常,这是维护的噩梦。

  

只要有很多要解释和重构的内容,这个答案就已经存在了很长时间,但是,这些更改使您的代码更易于理解和使用,以便您将来可以进一步更改/适应它。

     

如有任何疑问,请随时提问!

面向对象编程

面向对象编程(OOP)的全部目的在于处理对象(类,结构等),以便允许更高级别的Separation of Concerns(SoC)。通过将代码分成对象和文件,您可以允许更多相关的代码位进行处理。这很好,因为它使开发人员可以更轻松地检查,调试和排除代码故障。

您的代码可以分为多个对象,以使其更加抽象和独立,这将使您遇到(可能)遇到的下一个问题更容易解决(因此,您不必转向每次 都出现堆栈溢出:)。


1。您的“全局”变量的模块

首先,我认为您应该为“全局”变量(这些变量是您在两种形式中都引用的变量)声明一个模块。这样,您就可以将列表和词典移出frmManager

解决方案资源管理器中右键单击您的项目,然后转到Add > New Item...,然后选择Module并为其选择一个名称(我将其命名为{{1 }})。我们将在短时间内将变量移到那里...

GlobalMembers


2。 Friend Module GlobalMembers End Module

现在,您应该创建一个包含单个库的所有信息的类-这包括它包含的书籍和媒体。这不仅可以帮助您更轻松地从特定库中获取所需的所有信息,还可以简单地获取和修改其对不同媒体的选择。因此,Library列表现在已无用,因此可以删除。

该类将包含五个属性:

  • EquippedLibrary -库代码(例如Code)。
  • SVSU -库的名称(例如Name)。
  • Zahnow Library -库的显示方式,例如在ListBox中。
  • DisplayName -图书馆中所有{em> ID 书中的HashSet(Of String)
  • Books -库中有Media个非图书媒体的 ID

使用HashSet(Of String)是因为它提供了基于散列的查找机制(类似于HashSet),因此不允许重复。它基本上是一个没有重复的列表。

我之所以使用它,是因为它只会保存书籍和其他媒体的ID。这就是我们所需要的,因为我们可以使用每个ID在全局DictionaryBooks词典中查找相应的书籍或媒体。

这可以避免我们两次存储书籍,也可能导致我们的列表完全不同步。

现在,要添加类,请在 Solution Explorer 中右键单击您的项目,转到NonBookMedia,然后选择Add > New Item...

Class
  

请注意,代码中的XML注释(Public Class Library ''' <summary> ''' Gets or sets the library code. This must correspond to a key in the GlobalMembers.Libraries dictionary! ''' </summary> ''' <remarks></remarks> Public Property Code As String ''' <summary> ''' Gets or sets the name of the library. ''' </summary> ''' <remarks></remarks> Public Property Name As String ''' <summary> ''' Gets or sets the list of books (IDs) contained within the library. ''' Each value should correspond to a key in the GlobalMembers.Books dictionary. ''' </summary> ''' <remarks></remarks> Public Property Books As New HashSet(Of String) ''' <summary> ''' Gets or sets the list of non-book media (IDs) contained within the library. ''' Each value should correspond to a key in the GlobalMembers.NonBookMedia dictionary. ''' </summary> ''' <remarks></remarks> Public Property NonBookMedia As New HashSet(Of String) ''' <summary> ''' Gets the display name of the library. ''' </summary> ''' <remarks></remarks> Public ReadOnly Property DisplayName As String Get 'The text to display in for example a ListBox. Return Me.Name & " --- " & Me.Code End Get End Property ''' <summary> ''' Initializes a new instance of the Library class. ''' </summary> ''' <param name="Name">The name of the library.</param> ''' <param name="Code">The library code. This must correspond to a key in the GlobalMembers.Libraries dictionary!</param> ''' <remarks></remarks> Public Sub New(ByVal Name As String, ByVal Code As String) 'Constructor. Called whenever we write "New Library(...)". Me.Name = Name Me.Code = Code End Sub End Class 等)会在您键入代码时提供IntelliSense显示的描述,从而为您提供帮助。

     

IntelliSense example


3。 <summary></summary>Book

现在,我们将为图书和非图书媒体创建一个类。与我们到目前为止所做的没有太大不同。

Media类将包含:

  • Book -图书的ID(例如ID)。
  • 102 -这本书的名称(例如Name)。
  • Interpretive Klingon Poetry -图书的显示方式,例如,列表框。

DisplayName类将包含:

  • Media -(与上述相同)
  • ID -(与上述相同)
  • Name -(与上述相同)
  • DisplayName -这是什么类型的媒体(例如TypeCD等)。

像以前一样,首先为您的项目中的每一个添加一个新的Class文件。

  

注意:
  通常,您可能想对DVDBook类使用 polymorphism (即继承),但是我不确定您对OOP有多少了解,但我不知道想把这个答案太长了,所以我现在把它们做成两个独立的类。

Media

Book

Public Class Book ''' <summary> ''' Gets or sets the book's ID. This must correspond to a key in the GlobalMembers.Books dictionary! ''' </summary> ''' <remarks></remarks> Public Property ID As String ''' <summary> ''' Gets or sets the name of the book. ''' </summary> ''' <remarks></remarks> Public Property Name As String ''' <summary> ''' Gets the display name of the book. ''' </summary> ''' <remarks></remarks> Public ReadOnly Property DisplayName As String Get 'The text to display in for example a ListBox. Return Me.Name & " --- " & Me.ID End Get End Property ''' <summary> ''' Initializes a new instance of the Book class. ''' </summary> ''' <param name="Name">The name of the book.</param> ''' <param name="ID">The book's ID. This must correspond to a key in the GlobalMembers.Books dictionary!</param> ''' <remarks></remarks> Public Sub New(ByVal Name As String, ByVal ID As String) Me.Name = Name Me.ID = ID End Sub End Class 类:

Media
  

为获得更好的概述,下面是我们刚刚设计的类的图表:

     

Class Diagram


4。将全局变量移至模块

现在我们有了所有必需的类-Public Class Media ''' <summary> ''' Gets or sets the media's ID. This must correspond to a key in the GlobalMembers.NonBookMedia dictionary! ''' </summary> ''' <remarks></remarks> Public Property ID As String ''' <summary> ''' Gets or sets the name of the media. ''' </summary> ''' <remarks></remarks> Public Property Name As String ''' <summary> ''' Gets or sets the media type. ''' </summary> ''' <remarks></remarks> Public Property Type As String ''' <summary> ''' Gets the display name of the media. ''' </summary> ''' <remarks></remarks> Public ReadOnly Property DisplayName As String Get 'The text to display in for example a ListBox. Return Me.Type & " - " & Me.Name & " --- " & Me.ID End Get End Property ''' <summary> ''' Initializes a new instance of the Media class. ''' </summary> ''' <param name="Name">The name of the media.</param> ''' <param name="ID">The media's ID. This must correspond to a key in the GlobalMembers.NonBookMedia dictionary!</param> ''' <param name="Type">The media type (e.g. CD, DVD, etc.)</param> ''' <remarks></remarks> Public Sub New(ByVal Name As String, ByVal ID As String, ByVal Type As String) Me.Name = Name Me.ID = ID Me.Type = Type End Sub End Class LibraryBook-我们可以继续并将全局词典移至我们先前创建的模块。我们还将对它们进行一些更改...而不是每个字典都保留每个项目的代码/ ID和名称,而是它们保留代码/ ID 和实际项目(无论是图书馆,书籍还是某种媒体)。

这有助于我们更轻松地引用我们要获取的实际项目,(由于我们的类)已经包含了我们可能需要的所有信息。

现在的声明如下所示:

Media


5。设置列表框

现在,我们已经在后端进行了所有设置,现在是时候配置ListBox使其与新结构一起工作了,因为我们现在要存储 ,而不仅仅是在每个框中存储文本每个对象 。这对我们有很大帮助,因为我们可以直接引用选定的对象,而不必先在我们的词典之一中查找它。

在每个表单的Friend Module GlobalMembers ''' <summary> ''' A lookup table of all existing libraries. The Key of each entry must be the same as Library.Code. ''' </summary> ''' <remarks></remarks> Public Libraries As New Dictionary(Of String, Library) ''' <summary> ''' A lookup table of all existing books. The Key of each entry must be the same as Book.ID. ''' </summary> ''' <remarks></remarks> Public Books As New Dictionary(Of String, Book) ''' <summary> ''' A lookup table of all existing non-book media. The Key of each entry must be the same as Media.ID. ''' </summary> ''' <remarks></remarks> Public NonBookMedia As New Dictionary(Of String, Media) End Module 事件中,我们将设置ListBoxes的DisplayMember property,告诉他们应该使用每个项目的哪个属性来确定应显示的文本(这将是Load属性)。

  

注意:
  我们 不会 像我在上一个答案中建议的那样设置DisplayName属性,因为事实证明DataSource property可以正常工作也要设置。抱歉。

ValueMember

frmManager

Private Sub frmManager_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load 'Libraries. lstLibraries.DisplayMember = "DisplayName" 'Books. lstBooks.DisplayMember = "DisplayName" 'Non-book media. lstMedia.DisplayMember = "DisplayName" 'The rest of your code... End Sub

frmAssociationScreen


6。处理您的列表

我们现在已经建立了程序的整个基础。最后介绍功能。

向字典添加数据

由于我们的词典现在需要我们的自定义类,因此我们必须在添加它们之前初始化它们的实例。请注意,如何在两个地方指定图书馆的代码和书籍/媒体的ID。

Private Sub frmAssociationScreen_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    'Libraries.
    lstLibraries.DisplayMember = "DisplayName"

    'Books.
    lstAllBooks.DisplayMember = "DisplayName"
    lstBooksCurrLib.DisplayMember = "DisplayName"

    'Media.
    lstAllMedia.DisplayMember = "DisplayName"
    lstMediaCurrLib.DisplayMember = "DisplayName"


    'The rest of your code...
End Sub

刷新列表框

Libraries.Add("SVSU", New Library("Zahnow Library", "SVSU"))
Libraries.Add("BR", New Library("Fleschner Memorial Library", "BR"))
Libraries.Add("SDJ", New Library("Scott D. James Technical Repository", "SDJ"))

Books.Add("104", New Book("Data Structures for Fun and Profit", "104"))
Books.Add("103", New Book("Doing More With Less - Naval Lint Art", "103"))
Books.Add("102", New Book("Interpretive Klingon Poetry", "102"))
Books.Add("105", New Book("Programming with the Bidgoli", "105"))
Books.Add("101", New Book("Zen and the Art of Appliance Wiring", "101"))

NonBookMedia.Add("201", New Media("IEEE Computer: the Hits", "201", "CD"))
NonBookMedia.Add("203", New Media("Databases and You: the Video Experience", "203", "DVD"))
NonBookMedia.Add("202", New Media("The Pirates of Silicon Valley", "202", "DVD"))

删除项目(Sub populatelstLibrary() lstLibraries.Items.Clear() For Each library In Libraries lstLibraries.Items.Add(library.Value) 'Add the entire Library object directly. The ListBox manages display for us. Next End Sub Sub populatelstBooks() lstBooks.Items.Clear() For Each book In Books lstBooks.Items.Add(book.Value) 'Same goes for books... Next End Sub Sub populatelstBookMedia() lstMedia.Items.Clear() For Each bookMedia In nonBookMedia lstMedia.Items.Add(bookMedia.Value) '...and non-book media. Next End Sub

以下是从frmManager中删除所选库的方法。使用这种新结构,我们首先必须从frmManager获取所选的库 对象 ,然后使用其lstLibraries从字典中将其删除。 / p>

对书籍和非书籍媒体执行相同的步骤。

Code

刷新Private Sub btnDeleteLibrary_Click(sender As System.Object, e As System.EventArgs) Handles btnDeleteLibrary.Click 'Try casting the selected item as a Library. Dim selectedLibrary As Library = TryCast(lstLibraries.SelectedItem, Library) 'If an item is selected and casting succeeded the variable should not be null. If selectedLibrary IsNot Nothing Then 'Remove from dictionary. Libraries.Remove(selectedLibrary.Code) 'Refresh ListBox. populatelstLibrary() End If End Sub 中的列表框:

由于我们现在知道选择了哪个库对象及其包含的对象,因此我们可以过滤frmAssociationScreen框中的项目,从而显示我们已经选择的项目已经添加到我们的库中。

lstAll...

刷新当前库中已经存在的书籍/媒体的列表框:

Sub populatelstLibrary()
    lstLibraries.Items.Clear()

    For Each library In Libraries
        lstLibraries.Items.Add(library.Value)
    Next
End Sub

Sub populatelstBooks()
    lstAllBooks.Items.Clear()

    'Get the selected library.
    Dim selectedLibrary As Library = TryCast(lstLibraries.SelectedItem, Library)

    'If no library is selected, do not continue.
    If selectedLibrary Is Nothing Then Return

    For Each book In Books

        'Add all books that are NOT already in the library.
        'Check the book's dictionary key against the values in Library.Books.
        If Not selectedLibrary.Books.Contains(book.Key) Then
            lstAllBooks.Items.Add(book.Value)
        End If

    Next
End Sub

Sub populatelstBookMedia()
    lstAllMedia.Items.Clear()

    'Get the selected library.
    Dim selectedLibrary As Library = TryCast(lstLibraries.SelectedItem, Library)

    'If no library is selected, do not continue.
    If selectedLibrary Is Nothing Then Return

    For Each bookMedia In NonBookMedia

        'Add all media that is NOT already in the library.
        'Check the media's dictionary key against the values in Library.NonBookMedia.
        If Not selectedLibrary.NonBookMedia.Contains(bookMedia.Key) Then
            lstAllMedia.Items.Add(bookMedia.Value)
        End If

    Next
End Sub

Sub populatelstBooksCurrLib() lstBooksCurrLib.Items.Clear() 'Get the selected library. Dim selectedLibrary As Library = TryCast(lstLibraries.SelectedItem, Library) 'If no library is selected, do not continue. If selectedLibrary Is Nothing Then Return 'Iterate all book IDs in the library. For Each ID In selectedLibrary.Books 'Get the respective book from our dictionary (if the book doesn't exist it will be ignored). Dim book As Book = Nothing If Books.TryGetValue(ID, book) Then 'Add the book to our ListBox. lstBooksCurrLib.Items.Add(book) End If Next End Sub Sub populatelstMediaCurrLib() lstMediaCurrLib.Items.Clear() 'Get the selected library. Dim selectedLibrary As Library = TryCast(lstLibraries.SelectedItem, Library) 'If no library is selected, do not continue. If selectedLibrary Is Nothing Then Return 'Iterate all media IDs in the library. For Each ID In selectedLibrary.NonBookMedia 'Get the respective media from our dictionary (if the media doesn't exist it will be ignored). Dim media As Media = Nothing If NonBookMedia.TryGetValue(ID, Media) Then 'Add the media to our ListBox. lstMediaCurrLib.Items.Add(media) End If Next End Sub 的另一个列表中添加项目:

现在,当我们想从列表中添加书籍或非书籍媒体时,我们要做的就是将所选项目的ID添加到frmAssociationScreenLibrary.Books并刷新列表!

Library.NonBookMedia

Private Sub btnAddBook_Click(sender As System.Object, e As System.EventArgs) Handles btnAddBook.Click 'Get the selected library. Dim selectedLibrary As Library = TryCast(lstLibraries.SelectedItem, Library) 'If no library is selected, do not continue. If selectedLibrary Is Nothing Then Return 'Get the selected book. Dim selectedBook As Book = TryCast(lstAllBooks.SelectedItem, Book) 'If no book is selected, do not continue. If selectedBook Is Nothing Then Return 'Add the selected book to the library. 'If we for some reason add a duplicate, HashSet.Add() will return False and no exception will be thrown, so we're good to go! selectedLibrary.Books.Add(selectedBook.ID) 'Update lists. populatelstBooks() populatelstBooksCurrLib() End Sub Private Sub btnAddMedia_Click(sender As System.Object, e As System.EventArgs) Handles btnAddMedia.Click 'Get the selected library. Dim selectedLibrary As Library = TryCast(lstLibraries.SelectedItem, Library) 'If no library is selected, do not continue. If selectedLibrary Is Nothing Then Return 'Get the selected non-book media. Dim selectedMedia As Media = TryCast(lstAllMedia.SelectedItem, Media) 'If no media is selected, do not continue. If selectedMedia Is Nothing Then Return 'Add the selected media to the library. 'If we for some reason add a duplicate, HashSet.Add() will return False and no exception will be thrown, so we're good to go! selectedLibrary.NonBookMedia.Add(selectedMedia.ID) 'Update lists. populatelstBookMedia() populatelstMediaCurrLib() End Sub 的列表中删除项目:

删除时,与上述步骤大致相同。

frmAssociationScreen


最后一句话

要经历很多事情,需要重构的事情很多。但是,正如您所看到的,只需在类中进行一些额外的工作并进行一些重构,我们现在就可以缩短许多主要代码,并使其在将来更易于阅读,理解和操作。

希望这会有所帮助!

完整项目下载链接:
https://www.mydoomsite.com/sourcecodes/StackOverflow%20LibraryManagement.zip