提问人:RodH257 提问时间:8/24/2009 最后编辑:Thomas FlinkowRodH257 更新时间:3/9/2021 访问量:32843
我是如何在构造函数之后立即出现此NullReferenceException错误的?
How did I get this NullReferenceException error here right after the constructor?
问:
我已经有一个 asp.net 网站在我们的内部网上运行了几个星期。我刚刚从我的 application_error 电子邮件发送器方法收到一封电子邮件,其中包含未处理的异常。
这里是(我已经清理了一些路径以使其更好地显示)
例外:对象引用未设置为对象的实例。 堆栈跟踪:在 System.Collections.Generic.Dictionary'2.Insert (TKey 键,TValue 值,布尔值) 在 System.Collections.Generic.Dictionary'2.Add(TKey 键,TValue 值) 在 TimesheetDomain\DataMappers\StaffMemberData.cs:第 362 行中的 TimesheetDomain.DataMappers.StaffMemberData.ReadStaff(SqlDataReader 读取器)
在 TimesheetDomain.DataMappers.StaffMemberData.GetStaffMember(字符串) name) 在 时间表域\数据映射器\员工成员数据.cs:行 401
在 TimesheetDomain.ServiceLayer.TimesheetManager.GetUserFromName(字符串) name) 在 时间表域\服务层\时间表管理器.cs:行 199
在 UserVerification.GetCurrentUser() 在 \App_Code\UserVerification.cs:line 中 29 在 WebTimesheets.OnInit(EventArgs e) 在 \WebTimesheets\WebTimesheets.master.cs:行 159
在 System.Web.UI.Control.InitRecursive(控件 namingContainer) 在 System.Web.UI.Control.InitRecursive(控件 namingContainer) 在 System.Web.UI.Page.ProcessRequestMain(布尔值 includeStagesBeforeAsyncPoint, 布尔值 includeStagesAfterAsyncPoint)
基本上,它看起来像是我的 ReadStaff 方法出错,该方法读取数据读取器以构建工作人员对象。下面是一段代码:
while (reader != null && reader.Read())
{
StaffMember newMember = null;
string firstName = reader["FirstName"].ToString();
string lastName = reader["LastName"].ToString();
int staffID = (int)reader["StaffID"];
int employSection = (int)reader["EmploySection"];
StaffType employType = (StaffType)employSection;
string emailAddress = reader["EmailInt"].ToString();
int employCode = (int)reader["ibbwid"];
//check if they are an admin staff member
if (IsAdminStaff(employType))
{
newMember = new AdminOfficer(firstName, lastName, employType, staffID, emailAddress, employCode);
}
else
{
//check if they are a supervisor
if (IsASupervisor(staffID))
newMember = new Supervisor(firstName, lastName, employType, staffID, emailAddress, employCode);
else
newMember = new StaffMember(firstName, lastName, employType, staffID, emailAddress, employCode);
}
//add to identity map
if (!_staffMembers.ContainsKey(staffID))
_staffMembers.Add(staffID, newMember); //****THIS IS LINE 362*****
else
_staffMembers[staffID] = newMember;
}
(362 号线是倒数第三行)
我正在使用身份映射(只是阅读了关于模式的福勒书,并认为这是一个好主意 - 可能做错了,很高兴发表评论),但这并不过分相关,因为稍后我在其他地方使用该对象,所以如果我删除该块,就会发生。newMember
NullReferenceException
我正在努力了解那里的倒数第三行(这是出错的行)中到底是如何为空的。newMember
Resharper/VS 没有给我一个警告,它可能 - 因为我有 3 个构造函数可供选择。null
谁能建议我可以在哪里尝试修复这个错误?它只发生过一次,自网站上线以来,该方法已被调用数千次。
谢谢
[编辑] 根据要求,这是工作人员的 IComparer
/// <summary>
/// Comparer for staff members - compares on name
/// </summary>
public class StaffMemberComparer : IComparer
{
public int Compare(object x, object y)
{
//check they are staff members
if (x is StaffMember && y is StaffMember)
{
//do a simple string comparison on names
StaffMember staffX = x as StaffMember;
StaffMember staffY = y as StaffMember;
return String.Compare(staffX.FirstName, staffY.FirstName);
}
throw new Exception("This is for comparing Staff Members");
}
}
它用于 IComparable 实现
/// <summary>
/// IComparable implementaiton
/// </summary>
/// <param name="obj">object to compare to</param>
/// <returns></returns>
public int CompareTo(object obj)
{
StaffMemberComparer comparer = new StaffMemberComparer();
return comparer.Compare(this, obj);
}
答:
正如其他人所说,比较可能会导致问题。
是否有任何比较条件包含空值?具体来说,字符串属性?
即,如果 firstname 或 lastname 或 emailId 为 null,并且如果它用于比较,则在字典中进行比较时可能会失败。
编辑:主管和StaffMember以及AdminStaff类有什么关系?
在代码中,将这两个实例强制转换为 StaffMember。我的猜测是,如果 Supervisor 和 StaffMember 类不相关,这可能是一个问题。
EDIT2:字典实例的 scrope 是什么?它是否在应用程序级别/会话级别共享?是否有可能多个线程尝试从中读取/写入?
评论
我看不出任何明显的东西。我会运行一些 SQL 来检查数据库中是否有任何不良数据。问题可能是相关输入表单中的怪异错误。如果到目前为止,代码已经运行了数千次而没有发生任何事件,我会在有问题的代码块周围包装一些额外的异常处理/报告,这样您至少可以在下次发生时获得 staffId。
你可以在这样的事情上花费很多时间。最方便的方法可能只是让它在上述/受控条件下再次失败......假设它造成的中断程度是可接受的/可管理的/轻微的。
我很欣赏这不会满足立即知道的需求,但它可能是解决问题的最佳方法,尤其是在如此低的失败率下。
评论
它只发生过一次,而且 方法已被调用数千 自网站上线以来的次数。
读完这篇文章后,我可以得出结论,.NET 可能已经耗尽了它的内存,它无法创建更多的字典键,这可能真的不是你的错。但是,是的,当我们尝试在会话/应用程序变量中存储过多信息时,我们确实遇到了此类错误,从而增加了 Web 应用程序的内存占用。但是当我们的数字非常高时,我们会遇到这样的错误,比如在字典或列表中存储 10,000 个项目等。
模式很好,但你也必须意识到,我们使用数据库以关系格式存储信息,如果我们开始使用内存来存储类似的东西,那么我们就忽略了强大的数据库。数据库也可以为您缓存值。
这听起来可能很傻,但我们每 24 小时重新启动一次 Windows 服务器,在没有流量的午夜。这确实帮助我们摆脱了这些错误。我们定期按修复计划重新启动服务器,以清除所有缓存/日志。
这几乎可以肯定是一个线程问题 - 请参阅此问题及其公认的答案。
Dictionary<>.Insert()
如果在插入操作期间从另一个线程修改了字典实例,则会在内部抛出一个。NullReferenceException
评论
我看到这种异常的另一种方式,与线程无关,是在序列化字典时。在本例中,它是空的,但我仍然在反序列化实例的 Insert() 方法中获得了 NullReferenceException。
就我而言,简单的更改只是在反序列化后创建一个新实例。我不确定序列化是否只是破坏了字典,或者它是否是定义字典的类型。
就我而言,如果没有序列化代理项,这些类型是不可序列化的(我已经提供了这些),但也许字典中的某些内容在这里有问题。然而,字典又是空的,这仍然发生了。
从 .NET 4.0 开始,可以使用 ConcurrentDictionary 并避免与同时从多个线程操作同一字典相关的线程问题。
评论
if (!_staffMembers.ContainsKey(staffID)) _staffMembers.Add(staffID, newMember); else _staffMembers[staffID] = newMember;
_staffMembers[staffID] = newMember;