了解为什么 NullReferenceException 未得到处理?
Understand why NullReferenceException was unhandled?
我是初学者,我正在用 c# 编写一个简单的 Windows 表单程序(对我来说不是那么容易,但对专业程序员来说),它的工作方式如下:一个表单 (ContactForm class) 从用户那里获取输入(名字、姓氏、地址、电子邮件和 phone n),并通过属性将其存储到联系人 class 中的变量中。 Contact class 从其他三个 classes(Address、Email 和 Phone)调用属性和方法来存储和验证用户的输入。 Contact class 还包含一个覆盖 ToString 方法,该方法将包含用户输入的变量格式化为字符串。
此时,我尝试使用 ContactForm 调用此 ToString 方法并在 MessageBox 中显示字符串,它运行良好。但是后来我尝试用另一个 class、Customer 调用该方法,它有一个 Contact class 的对象,这是一场灾难。编译器不断为表示为 null 的 Contact class (m_contact) 的对象关联 NullReferenceException。这是代码:
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 方法:
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方法,但上面那些检查方法肯定不是问题:
public bool CheckEmail()
{
bool ok = false;
if ((!string.IsNullOrEmpty(m_personal)) || (!string.IsNullOrEmpty(m_work)))
ok = true;
else
ok = false;
return ok;
}
这是 ContactForm class 中显示联系人 class 的 ToString 方法的代码,完全没有问题:
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);
}
}
}
}
此外,MainForm 调用 Customer ToString 方法以在 MessageBox 上显示消息。这是 MainForm 中的方法:
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());
}
}
为什么 Customer class 中的 m_contact 为空,而 ContactForm class 中的却不是?抱歉 post 的篇幅,我真的很难理解。谢谢!
首先,您必须检查 m_contact
是否不为空,然后尝试对该对象调用方法 ToString
。否则你会得到 NullReferenceException,因为你在空对象上调用方法。
基本上,重写
**if ((!string.IsNullOrEmpty(m_contact.ToString())) && (m_contact != null) && (m_contact.Validate()))**
{
strOut = m_contact.ToString();
}
else
strOut = null;
至:
if (m_contact != null && !string.IsNullOrEmpty(m_contact.ToString()) && m_contact.Validate())
{
strOut = m_contact.ToString();
}
else
strOut = null;
我是初学者,我正在用 c# 编写一个简单的 Windows 表单程序(对我来说不是那么容易,但对专业程序员来说),它的工作方式如下:一个表单 (ContactForm class) 从用户那里获取输入(名字、姓氏、地址、电子邮件和 phone n),并通过属性将其存储到联系人 class 中的变量中。 Contact class 从其他三个 classes(Address、Email 和 Phone)调用属性和方法来存储和验证用户的输入。 Contact class 还包含一个覆盖 ToString 方法,该方法将包含用户输入的变量格式化为字符串。 此时,我尝试使用 ContactForm 调用此 ToString 方法并在 MessageBox 中显示字符串,它运行良好。但是后来我尝试用另一个 class、Customer 调用该方法,它有一个 Contact class 的对象,这是一场灾难。编译器不断为表示为 null 的 Contact class (m_contact) 的对象关联 NullReferenceException。这是代码:
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 方法:
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方法,但上面那些检查方法肯定不是问题:
public bool CheckEmail()
{
bool ok = false;
if ((!string.IsNullOrEmpty(m_personal)) || (!string.IsNullOrEmpty(m_work)))
ok = true;
else
ok = false;
return ok;
}
这是 ContactForm class 中显示联系人 class 的 ToString 方法的代码,完全没有问题:
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);
}
}
}
} 此外,MainForm 调用 Customer ToString 方法以在 MessageBox 上显示消息。这是 MainForm 中的方法:
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());
}
}
为什么 Customer class 中的 m_contact 为空,而 ContactForm class 中的却不是?抱歉 post 的篇幅,我真的很难理解。谢谢!
首先,您必须检查 m_contact
是否不为空,然后尝试对该对象调用方法 ToString
。否则你会得到 NullReferenceException,因为你在空对象上调用方法。
基本上,重写
**if ((!string.IsNullOrEmpty(m_contact.ToString())) && (m_contact != null) && (m_contact.Validate()))**
{
strOut = m_contact.ToString();
}
else
strOut = null;
至:
if (m_contact != null && !string.IsNullOrEmpty(m_contact.ToString()) && m_contact.Validate())
{
strOut = m_contact.ToString();
}
else
strOut = null;