为什么我得到错误“NullReferenceException未处理”?

时间:2013-09-11 22:37:02

标签: c# compiler-errors null nullpointerexception nullreferenceexception

我正在尝试创建一个滑块益智游戏,当我在form1中调用myBoard.paint(e.Graphics)时,我不断收到错误“NullReferenceException未处理”。请帮帮我!!!

这是我的Form1代码(如果我需要发布我的其他类代码,请告诉我):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

namespace SliderPuzzle
{
    public partial class Form1 : Form
    {
        private int tileSize;
        private int rowsCols;
        private SlidePuzzle myBoard;
        private Stopwatch timer;
        private int moveCount;

        public Form1()
        {
            InitializeComponent();
            pictureBox1.TabIndex = 3;
            pictureBox1.Size = new Size(100, 50);
            pictureBox1.Location = new Point(16, 71);
            pictureBox1.BackColor = Color.PaleGreen;
            pictureBox1.BorderStyle = BorderStyle.Fixed3D;
            pictureBox1.TabStop = false;
            tileSize = imageList1.ImageSize.Width;
            rowsCols = 3;
            pictureBox1.Width = rowsCols * tileSize;
            pictureBox1.Height = rowsCols * tileSize;
        }

        public void initGame()
        {
            myBoard = new SlidePuzzle(rowsCols, tileSize, imageList1);
            timer = new Stopwatch();
            moveCount = 0;
            timer.Start();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            initGame();
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
          this.myBoard.paint(e.Graphics);
        }

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (myBoard.move(e.Y / tileSize, e.X / tileSize))
                ++moveCount;
            Refresh();
            if (!myBoard.winner())
                return;
            timer.Stop();
            if (MessageBox.Show(string.Format("You won!!\nIt took you {0} moves and {1:F2} seconds.\nPlay again?", (object)moveCount, (object)timer.Elapsed.TotalSeconds), "Game Over", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.No)
            {
                Close();
            }
            else
            {
                initGame();
                Refresh();
            }
        }
    }
}

更新#1:好的,所以我移动了myBoard = new SlidePuzzle(rowsCols,tileSize,imageList1);到我的构造函数,但现在没有任何图像出现在它上面。以下是它看起来像它应该是什么样子:enter image description here

编辑#2:好的,我把它移回原来的位置然后放

if (this.myBoard != null)
        this.myBoard.paint(e.Graphics);
相反,它工作得更好,看起来也更好。但是没有出现的图像仍然存在问题。

编辑#3:这是SliderPuzzle.Paint代码:

        public void paint(Graphics g)
    {
        for (int r = 0; r < this.myGrid.getNumRows(); ++r)
        {
            for (int c = 0; c < this.myGrid.getNumCols(); ++c)
                this.myGrid.get(new Location(r, c)).paint(g);
        }
    }

编辑#4:这是SliderPuzzle类的代码:

using System;
using System.Drawing;
using System.Windows.Forms;

namespace SliderPuzzle
{
    internal class SlidePuzzle
    {
        private static Random rand = new Random();
        private int myTileSize;
        private BoundedGrid myGrid;
        private ImageList myImages;
        private Location myBlankLoc;

        static SlidePuzzle()
        {
        }

        public SlidePuzzle(int rowsCols, int tileSize, ImageList images)
        {
            this.myTileSize = tileSize;
            this.myGrid = new BoundedGrid(rowsCols, rowsCols);
            this.myImages = images;
            this.myBlankLoc = new Location(rowsCols - 1, rowsCols - 1);
            this.initBoard();
        }

        private void initBoard()
        {
            int index1 = 0;
            for (int r = 0; r < this.myGrid.getNumRows(); ++r)
            {
                for (int c = 0; c < this.myGrid.getNumCols(); ++c)
                {
                    this.myGrid.put(new Location(r, c), new Tile(index1, this.myTileSize, new Location(r, c), this.myImages.Images[index1]));
                    ++index1;
                }
            }
            for (int index2 = 0; index2 < 1000; ++index2)
            {
                Location adjacentLocation = this.myBlankLoc.getAdjacentLocation(SlidePuzzle.rand.Next(4) * 90);
                if (this.myGrid.isValid(adjacentLocation))
                {
                    this.swap(this.myBlankLoc, adjacentLocation);
                    this.myBlankLoc = adjacentLocation;
                }
            }
        }

        public bool move(int row, int col)
        {
            Location loc1 = new Location(row, col);
            if (Math.Abs(this.myBlankLoc.getRow() - row) + Math.Abs(this.myBlankLoc.getCol() - col) != 1)
                return false;
            this.swap(loc1, this.myBlankLoc);
            this.myBlankLoc = loc1;
            return true;
        }

        public bool winner()
        {
            int num = 0;
            for (int r = 0; r < this.myGrid.getNumRows(); ++r)
            {
                for (int c = 0; c < this.myGrid.getNumCols(); ++c)
                {
                    if (this.myGrid.get(new Location(r, c)).getValue() != num)
                        return false;
                    ++num;
                }
            }
            return true;
        }

        private void swap(Location loc1, Location loc2)
        {
            Tile tile1 = this.myGrid.put(loc2, this.myGrid.get(loc1));
            Tile tile2 = this.myGrid.put(loc1, tile1);
            tile1.setLocation(loc1);
            tile2.setLocation(loc2);
        }

        public void paint(Graphics g)
        {
            for (int r = 0; r < this.myGrid.getNumRows(); ++r)
            {
                for (int c = 0; c < this.myGrid.getNumCols(); ++c)
                    this.myGrid.get(new Location(r, c)).paint(g);
            }
        }
    }
}

更新#5:这是瓷砖类:

using System.Drawing;

namespace SliderPuzzle
{
    internal class Tile
    {
        private int myValue;
        private int mySize;
        private Location myLoc;
        private Image myImage;

        public Tile(int value, int tileSize, Location loc, Image img)
        {
            this.myValue = value;
            this.mySize = tileSize;
            this.myLoc = loc;
            this.myImage = img;
        }

        public int getValue()
        {
            return this.myValue;
        }

        public void setLocation(Location newLoc)
        {
            this.myLoc = newLoc;
        }

        public void paint(Graphics g)
        {
            g.DrawImage(this.myImage, this.myLoc.getCol() * this.mySize, this.myLoc.getRow() * this.mySize);
        }
    }
}

编辑#6:这是位置类:

namespace SliderPuzzle
{
    internal class Location
    {
        public const int LEFT = -90;
        public const int RIGHT = 90;
        public const int HALF_LEFT = -45;
        public const int HALF_RIGHT = 45;
        public const int FULL_CIRCLE = 360;
        public const int HALF_CIRCLE = 180;
        public const int AHEAD = 0;
        public const int NORTH = 0;
        public const int NORTHEAST = 45;
        public const int EAST = 90;
        public const int SOUTHEAST = 135;
        public const int SOUTH = 180;
        public const int SOUTHWEST = 225;
        public const int WEST = 270;
        public const int NORTHWEST = 315;
        private int row;
        private int col;

        public Location(int r, int c)
        {
            this.row = r;
            this.col = c;
        }

        public int getRow()
        {
            return this.row;
        }

        public int getCol()
        {
            return this.col;
        }

        public Location getAdjacentLocation(int direction)
        {
            int num1 = (direction + 22) % 360;
            if (num1 < 0)
                num1 += 360;
            int num2 = num1 / 45 * 45;
            int num3 = 0;
            int num4 = 0;
            if (num2 == 90)
                num3 = 1;
            else if (num2 == 135)
            {
                num3 = 1;
                num4 = 1;
            }
            else if (num2 == 180)
                num4 = 1;
            else if (num2 == 225)
            {
                num3 = -1;
                num4 = 1;
            }
            else if (num2 == 270)
                num3 = -1;
            else if (num2 == 315)
            {
                num3 = -1;
                num4 = -1;
            }
            else if (num2 == 0)
                num4 = -1;
            else if (num2 == 45)
            {
                num3 = 1;
                num4 = -1;
            }
            return new Location(this.getRow() + num4, this.getCol() + num3);
        }

        public bool equals(Location other)
        {
            if (this.getRow() == other.getRow())
                return this.getCol() == other.getCol();
            else
                return false;
        }

        public int hashCode()
        {
            return this.getRow() * 3737 + this.getCol();
        }

        public int compareTo(Location otherLoc)
        {
            if (this.getRow() < otherLoc.getRow())
                return -1;
            if (this.getRow() > otherLoc.getRow())
                return 1;
            if (this.getCol() < otherLoc.getCol())
                return -1;
            return this.getCol() > otherLoc.getCol() ? 1 : 0;
        }

        public string toString()
        {
            return "(" + (object)this.getRow() + ", " + (string)(object)this.getCol() + ")";
        }
    }
}

编辑#7:这是最后一个类,BoundedGrid类:

using System;
using System.Collections.Generic;

namespace SliderPuzzle
{
    internal class BoundedGrid
    {
        private Tile[,] occupantArray;

        public BoundedGrid(int rows, int cols)
        {
            this.occupantArray = new Tile[rows, cols];
        }

        public int getNumRows()
        {
            return this.occupantArray.GetLength(0);
        }

        public int getNumCols()
        {
            return this.occupantArray.GetLength(1);
        }

        public bool isValid(Location loc)
        {
            if (0 <= loc.getRow() && loc.getRow() < this.getNumRows() && 0 <= loc.getCol())
                return loc.getCol() < this.getNumCols();
            else
                return false;
        }

        public List<Location> getOccupiedLocations()
        {
            List<Location> list = new List<Location>();
            for (int r = 0; r < this.getNumRows(); ++r)
            {
                for (int c = 0; c < this.getNumCols(); ++c)
                {
                    Location loc = new Location(r, c);
                    if (this.get(loc) != null)
                        list.Add(loc);
                }
            }
            return list;
        }

        public Tile get(Location loc)
        {
            if (!this.isValid(loc))
                throw new Exception("Location " + (object)loc + " is not valid");
            else
                return this.occupantArray[loc.getRow(), loc.getCol()];
        }

        public Tile put(Location loc, Tile obj)
        {
            if (!this.isValid(loc))
                throw new Exception("Location " + (object)loc + " is not valid");
            if (obj == null)
                throw new NullReferenceException("obj == null");
            Tile tile = this.get(loc);
            this.occupantArray[loc.getRow(), loc.getCol()] = obj;
            return tile;
        }

        public Tile remove(Location loc)
        {
            if (!this.isValid(loc))
                throw new Exception("Location " + (object)loc + " is not valid");
            Tile tile = this.get(loc);
            this.occupantArray[loc.getRow(), loc.getCol()] = (Tile)null;
            return tile;
        }
    }
}

编辑#8:当我点击图片框时,程序崩溃并且它显示了timer.Stop();在form1给我一个NullReferenceException !!!

编辑#9:好的,有用......我发现图像仍然没有出现,但我认为它们永远不会被放置在网格上。当我点击网格(仍然没有图像)它说我赢了。这应该只在我将瓷砖移动到正确的顺序后显示。知道发生了什么事吗?

编辑#10:我的程序现在终于有效了!事实证明我在form1的构造函数中有一些错位,现在一切正常!图像显示和一切!这有多酷!!!

感谢你们每个人的贡献,我现在将在我的学校项目中获得一个伟大的等级!

3 个答案:

答案 0 :(得分:3)

这是令你头疼的问题之一。当你可以保证事件永远不会被无序调用时,试图确定事件的确切顺序是很好的。不幸的是,Paint事件是在各种奇怪的时间被触发的事件,甚至可能在Load事件之前被触发。

唯一真正的答案是 从不 依赖于按特定顺序触发的事件。在尝试绘制它之前,请务必检查您的myBoard对象是否有效:

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    if (this.myBoard != null)
        this.myBoard.paint(e.Graphics);
}

是的,正如其他人所指出的那样,最好尽快创建所有对象 - 例如在构造函数中,毕竟构造函数是 。即使这样,您仍然可以通过构造函数中的操作触发事件,这会破坏您的一整天。应该在构造函数代码中尽可能晚地设置偶数处理程序以解决此问题。

经验法则:

  • 如果您要创建将在事件处理程序中使用的自定义对象,请始终在构造函数中调用InitializeComponent之前尝试创建和初始化它们。

  • 尽可能晚地连接你的事件处理程序,特别是像Paint之类的事情 - 它在构造函数完成之前没用,所以最后在构造函数中这样做。

答案 1 :(得分:2)

您的实际Form1_Load事件永远不会被调用(您正在初始化您的电路板的事件)。 在Form1构造函数this.Load +=Form1_Load;

的末尾添加此代码

答案 2 :(得分:-1)

您的pictureBox1.Paint事件在Form1.Load事件发生之前提出。移动

myBoard = new SlidePuzzle(rowsCols, tileSize, imageList1);

到你的构造函数,你应该没问题。

相关问题