关于c#:了解为什么NullReferenceException未处理?

Understand why NullReferenceException was unhandled?

本问题已经有最佳答案,请猛点这里访问。

我是一个初学者,我正在用C语言编写一个简单的Windows窗体程序(对我来说不是那么容易,但对一个专业的程序员来说),它的工作原理是这样的:一个窗体(contactForm类)从用户那里获得输入(名字、姓氏、地址、电子邮件和电话号码),并通过属性将其存储到contact类中的变量中。contact类从其他三个类(地址、电子邮件和电话)调用属性和方法来存储和验证用户的输入。contact类还包含一个override-toString方法,该方法将包含用户输入的变量格式化为字符串。在这一点上,我尝试用contactForm调用这个toString方法,并在一个消息框中显示该字符串,它工作得很好。但后来我尝试用另一个类(customer)调用该方法,该类具有contact类的对象,这是一个灾难。编译器不断为contact类(m_contact)的对象(表示为空)重新发出nullreferenceexception。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class Customer
{
    private Contact m_contact;
    private int m_ID;

    public Customer()
    {

    }public Customer(Contact contactIn)
    {

    }public Customer(Contact contactIn, int id)
    {
        if (m_contact != null)
        {
            m_contact = new Contact();
            m_contact = contactIn;
        }
        m_ID = id;
    }public Contact ContactData
    {
        get { return m_contact; }
        set {
            if (value != null)
                m_contact = value; }
    }public int ID
    {
        get { return m_ID; }
        set { m_ID = value; }
    }
    public override string ToString()
    {
        string strOut = string.Empty;
        **if ((!string.IsNullOrEmpty(m_contact.ToString())) && (m_contact != null) && (m_contact.Validate()))**
        {
            strOut = m_contact.ToString();
        }
        else
            strOut = null;
        return strOut;
    }
}

}星号中的行是发现错误的行。这是m_contact.validate方法:

1
2
3
4
5
6
7
8
9
public bool Validate()
    {
        bool ok = false;
        if (!string.IsNullOrEmpty(m_firstName) && (!string.IsNullOrEmpty(m_lastName)) && m_address.CheckData() && m_email.CheckEmail() && m_phone.CheckPhone())
            ok = true;
        else
            ok = false;
        return ok;
    }

为了更清晰起见,这是email.checkemail方法,但上述检查方法绝对不是问题:

1
2
3
4
5
6
7
8
9
public bool CheckEmail()
    {  
        bool ok = false;
        if ((!string.IsNullOrEmpty(m_personal)) || (!string.IsNullOrEmpty(m_work)))
            ok = true;
        else
            ok = false;
        return ok;
    }

这是来自contactForm类的代码,显示了contact类的toString方法,完全没有问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
public partial class ContactForm : Form
{
    private Contact m_contact;
    private bool m_closeForm;
    public ContactForm(string title)
    {
        InitializeComponent();
        m_contact = new Contact();
        this.Text = title;
        InitializeGUI();
    }public Contact ContactData
    {
        get { return m_contact; }
        set
        {
            if (value != null)
            m_contact = value;
        }
    }private void InitializeGUI()
    {
        txtFirstName.Text = string.Empty;
        txtLastName.Text = string.Empty;
        txtHomePhone.Text = string.Empty;
        txtCellPhone.Text = string.Empty;
        txtEMailBus.Text = string.Empty;
        txtEMailPr.Text = string.Empty;
        txtStreet.Text = string.Empty;
        txtCity.Text = string.Empty;
        txtZip.Text = string.Empty;
        FillCountryComboBox();
        cmbCountry.SelectedIndex = (int)Countries.Sverige;
        m_closeForm = true;
    }private void FillCountryComboBox()
    {
        cmbCountry.Items.AddRange(Enum.GetNames(typeof(Countries)));
    }

    private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        if (m_closeForm)
            e.Cancel = false;
        else
            e.Cancel = true;
    }public bool ReadInput()
    {
        m_contact.FirstName = txtFirstName.Text;
        m_contact.LastName = txtLastName.Text;
        m_contact.AddressData = ReadAddress();
        m_contact.EmailData = ReadEmail();
        m_contact.PhoneData = ReadPhone();

        bool ok = m_contact.Validate();
        if (ok)
        {
            return true;
        }
        else
        {
            MessageBox.Show("Please provide at least your firstname, lastname, phone number, email address, city and country");
            return false;
        }
    }private Address ReadAddress()
    {
        Address m_address = new Address();

        m_address.Street = txtStreet.Text;
        m_address.City = txtCity.Text;
        m_address.ZipCode = txtZip.Text;
        m_address.Country = (Countries)cmbCountry.SelectedIndex;
        return m_address;
    }private Email ReadEmail()
    {
        Email m_email = new Email();

        m_email.Work = txtEMailBus.Text;
        m_email.Personal = txtEMailPr.Text;
        return m_email;
    }private Phone ReadPhone()
    {
        Phone m_phone = new Phone();

        m_phone.Home = txtHomePhone.Text;
        m_phone.Other = txtCellPhone.Text;
        return m_phone;
    }

    private void btnOK_Click(object sender, EventArgs e)
    {
        if (ReadInput())
        {
            UpdateGUI();
            m_closeForm = true;
            this.Close();
        }
        else
            m_closeForm = false;
    }public void UpdateGUI()
    {
        string strOut = m_contact.ToString();
        MessageBox.Show(strOut);
    }
    }
}

}此外,主窗体调用customer-toString方法以在消息框上显示消息。这是主窗体中的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private void btnAdd_Click(object sender, EventArgs e)
    {
        ContactForm contForm = new ContactForm("Add a new customer");
        Customer cust = new Customer();
        int index = lstResults.SelectedIndex;

        if (index != -1)
            contForm.ContactData = customerMngr.GetCustomer(index).ContactData;

        if (contForm.ShowDialog() == DialogResult.OK)
        {
            lstResults.Items.Clear();


            if (contForm.ReadInput() && (!String.IsNullOrEmpty(cust.ToString()) && (cust != null)))
            {
                MessageBox.Show(cust.ToString());
            }
        }

为什么客户类中的m_联系人为空,而不是contactForm类中的联系人?抱歉,这篇文章篇幅太长了,我真的很难理解。谢谢您!


首先,必须检查,如果m_contact不为空,然后尝试对该对象调用方法ToString。否则,您将得到NullReferenceException,因为您正在对空对象调用方法。

基本上,重写

1
2
3
4
5
6
 **if ((!string.IsNullOrEmpty(m_contact.ToString())) && (m_contact != null) && (m_contact.Validate()))**
        {
            strOut = m_contact.ToString();
        }
        else
            strOut = null;

到:

1
2
3
4
5
6
 if (m_contact != null && !string.IsNullOrEmpty(m_contact.ToString()) && m_contact.Validate())
 {
     strOut = m_contact.ToString();
 }
 else
     strOut = null;