VB.Net 2010 "Object reference not set to an instance of an object." 以列表作为值从字典声明变量时

VB.Net 2010 "Object reference not set to an instance of an object." when declaring a variable from a Dictionary with a list as the value

这是一个学校的编程项目(不是评估或作业,所以我没有作弊),我必须在其中制作 7 段显示来源 1。我决定不采用传统方式,而是手动将每个 RectangeShape 设置为在按下的每个按钮上可见以显示数字;将相应的数字和要打开的 RectangleShape(s) 作为键值对存储在字典中。我对 Python 有一些了解,所以这就是我的灵感来源。我的表格 Source 2 有 7 RectangleShape(s) 和 10 Button(s)。作为一个实验,因为这是我第一次在 VB.net 中使用 DictionariesLists,我决定暂时只对数字 1 进行尝试(shp4shp5 应该是可见的)。这是我制作的词典:

Dim Numbers As New Dictionary(Of Integer, List(Of PowerPacks.Shape)) From {{1, New List(Of PowerPacks.Shape) From {shp4, shp5}}, {2, New List(Of PowerPacks.Shape) From {shp2, shp3}}}

这是按钮 (btn1) 的代码:

Private Sub btn1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn1.Click

    Dim Thing As PowerPacks.Shape = Numbers(1)(0)
    Thing.Visible = True

End Sub

当程序到达 Thing.Visible = True 行时,它会抛出一个错误。这是一个 NullReferenceException 声明 Object reference not set to an instance of an object. 关于如何解决这个问题的任何想法?

来源

来源 1:

来源 2:

编程不是魔法。它的工作原理与您预期的差不多。如果您在 Dictionary 中从 List 中获取 Nothing,那么您必须将 Nothing 放入。您在发布之前是否使用了调试器?当这一行被执行时,你真的看过 shp2 等的值吗:

Dim Numbers As New Dictionary(Of Integer, List(Of PowerPacks.Shape)) From {{1, New List(Of PowerPacks.Shape) From {shp4, shp5}}, {2, New List(Of PowerPacks.Shape) From {shp2, shp3}}}

根据你在第二个代码片段中使用那个 Numbers 变量,它必须是一个成员变量,这意味着第一个代码片段在任何方法之外,这意味着它在class 构造函数,这意味着此时还没有创建控件,这意味着任何引用控件的字段只能是Nothing。如果您在该行上放置了一个断点并使用了调试器,那么您应该已经看到了。

解决方案是在创建 Shapes 之前将它们实际添加到集合中。这意味着在调用 InitializeComponent 之后。这意味着您可以创建自己的构造函数并根据需要在那里执行,但您可能应该只在 Load 事件处理程序中执行。只需声明 Dictionary 变量而不创建对象:

Private numbers As Dictionary(Of Integer, PowerPacks.Shape())

请注意,我提供了一个显式访问修饰符,您应该始终对所有成员执行此操作,并且还以小写字母开头的名称,您可能应该对所有私有字段执行此操作。然后在 load 事件处理程序中创建对象:

numbers As New Dictionary(Of Integer, PowerPacks.Shape()) From {{1, {shp4, shp5}},
                                                                {2, {shp2, shp3}}}

我冒昧地使用数组而不是 Lists 来简化它,因为它没有任何价值。

在您的 7 段显示表单中,我会使用一个 List (of String),其中包含为每个字典键(数字)打开的矩形。这将需要首先以编程方式将 7 个形状添加到表单上(看起来您已经编写了代码),然后在每个按钮(对于数字)中只需选择打开的矩形并更改它们的背景颜色。将所有形状(矩形)“前端加载”到字典中可能是不必要的,因为它们已经手动固定在表单上。如果不是,则提取将它们放在表单上的代码,然后 运行 第一次,一次,当表单加载时。使用这种方法,您不必再担心形状问题。

在表格 1 中,添加:

Dim dicRSBackColor As New Dictionary(Of Integer, List(Of String))
Dim SC As New ShapeContainer

在Form1_Load中添加以下内容:

   'define each of the 7 rectangles using, e.g.: 
    Dim myrec4 As New RectangleShape
    myrec4.Name = "shp4"
    myrec4.Visible = True
    myrec4.BringToFront()
    'add locations and size to myrec4
    myrec4.Top=100
    myrec4.Left=100
    myrec4.Width=10
    myrec4.Height=100
    'then add myrec4 to Shape container
    SC.Shapes.Add(myrec4)
    'add myrec4 to Form1
    Me.Controls.Add(myrec4)
    'do the above for all 7 rectangleshapes

    'For the dictionary, add number 1's rectangleshape (turned on)
    Dim mylist As List(Of String)
    mylist.Add("shp4")
    mylist.Add("shp5")
    dicRSBackColor.Add(1, mylist)
    'add number 2 rectangles (turned on)
    mylist.Clear()
    mylist.Add("shp1")
    mylist.Add("shp3")
    mylist.Add("shp4")
    mylist.Add("shp6")
    mylist.Add("shp7")
    dicRSBackColor.Add(2, mylist)
    'continue until all 7 rec's added

最后,在按钮 _Click for number 1 中,使用以下内容:

'First change background color of all rectangleshapes to Form1's back color
For Each rs As RectangleShape In Me.SC.Shapes
    rs.BackColor = Me.BackColor
Next
'Now pull the list of shapes that are turned on for number 1 using the dictionary
Dim mylist1 As List(Of String)
mylist1 = dicRSBackColor(1) 'you're pulling the value for key=1, which is a list of strings
'use a double loop and find out when the list value is the same as the name of the rectangleshape, and then set the back color to orange
For Each item In mylist1
    For Each rs As RectangleShape In Me.SC.Shapes
        If item = rs.Name Then rs.BackColor = Color.Orange
    Next
Next