【问题标题】:How did I get this NullReferenceException error here right after the constructor?我是如何在构造函数之后得到这个 NullReferenceException 错误的?
【发布时间】:2010-11-22 03:49:14
【问题描述】:

我有一个asp.net 网站在我们的Intranet 上运行了几个星期。我刚收到一封来自我的 application_error emailer 方法的电子邮件,其中包含未处理的异常。

在这里(我已经清理了一些路径以使其更好地显示)

异常:对象引用未设置为对象的实例。 堆栈跟踪:在 System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value) 在 TimesheetDomain.DataMappers.StaffMemberData.ReadStaff(SqlDataReader reader) 在 TimesheetDomain\DataMappers\StaffMemberData.cs:line 362

在 TimesheetDomain.DataMappers.StaffMemberData.GetStaffMember(字符串 名称)在 TimesheetDomain\DataMappers\StaffMemberData.cs:line 401

在 TimesheetDomain.ServiceLayer.TimesheetManager.GetUserFromName(字符串 名称)在 TimesheetDomain\ServiceLayer\TimesheetManager.cs:line 199

在 UserVerification.GetCurrentUser() 在 \App_Code\UserVerification.cs:line 29 在 WebTimesheets.OnInit(EventArgs e) 在 \WebTimesheets\WebTimesheets.master.cs:line 159

在 System.Web.UI.Control.InitRecursive(控制 命名容器)在 System.Web.UI.Control.InitRecursive(控制 命名容器)在 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 行是倒数第三行) 我正在使用身份图(只是阅读 fowlers 关于模式的书,并认为这是一个好主意 - 可能做错了,对 cme​​ts 感到高兴)但这并不太相关,因为稍后我在其他地方使用 newMember 对象所以如果我删除该块 NullReferenceException 将会发生。

我很难看到newMember 在最后一行的第三行(这是错误的行)中究竟是如何为空的。

Resharper/VS 没有警告我它可能是null - 因为我可以选择 3 个构造函数。

谁能建议我在哪里可以尝试修复此错误?它只发生过一次,自网站上线以来,该方法已被调用了数千次。

谢谢

[编辑] 根据要求,这是工作人员的 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);
}

【问题讨论】:

  • TimesheetDomain\DataMappers\StaffMemberData.cs:line 362 是哪一行?
  • 这与实际问题无关,但您可以将整个 if (!_staffMembers.ContainsKey(staffID)) _staffMembers.Add(staffID, newMember); else _staffMembers[staffID] = newMember; 替换为 _staffMembers[staffID] = newMember;。如果它不存在,它将添加密钥。
  • 对不起(没有说得很清楚)362 行是我代码块中的第三行,它的 _staffMembers.Add(staffID, newMember);谢谢 mehrdad,我会记住的,我以为我这样做是有原因的,但现在不记得了,所以我会试试你的版本

标签: c# asp.net nullreferenceexception


【解决方案1】:

几乎可以肯定是线程问题 - 请参阅 this question and its accepted answer

如果在插入操作期间从另一个线程修改了字典实例,Dictionary&lt;&gt;.Insert() 将在内部抛出 NullReferenceException

【讨论】:

  • 这完全不明显,特别是如果你只从外面看到一个字典...
【解决方案2】:

从 .NET 4.0 开始,您可以使用 ConcurrentDictionary 并避免与同时从多个线程操作同一字典相关的线程问题。

【讨论】:

    【解决方案3】:

    它只发生过一次 方法已被称为数千 自网站上线以来的时间。

    读完这篇文章后,我可以得出结论,.NET 可能已经耗尽了它的内存并且它无法创建更多的 Dictionary 键,这可能不是你的错。但是,是的,当我们尝试在会话/应用程序变量中存储太多信息时确实遇到了这类错误,从而增加了 Web 应用程序的内存占用。但是当我们的数字非常高时,我们会遇到这样的错误,比如在 Dictionary 或 List 中存储 10,000 个项目等。

    模式很好,但你也必须意识到,我们使用数据库来存储关系格式的信息,如果我们开始使用内存来存储类似的东西,那么我们就忽略了强大的数据库。数据库也可以为您缓存值。

    这听起来可能很愚蠢,但我们的 Windows 服务器每 24 小时重新启动一次,在没有流量的午夜。这确实帮助我们摆脱了这些错误。我们会按固定时间表定期重启服务器,以清除所有缓存/日志。

    【讨论】:

      【解决方案4】:

      我看不到任何明显的东西。我会运行一些 SQL 来检查数据库中是否存在任何错误数据。问题可能是相关输入表单中的异常错误。如果到目前为止代码已经运行了数千次而没有发生任何事故,我会在有问题的代码块周围包装一些额外的异常处理/报告,这样你至少可以在下次发生时获得一个 staffId。

      您可能会在这样的事情上花费大量时间。最方便的方法可能只是让它在上述/受控条件下再次失败......假设它造成的破坏程度是可接受的/可管理的/轻微的。

      我明白这不能满足即时的了解需求,但它可能是解决问题的最佳方法,尤其是在故障率如此低的情况下。

      【讨论】:

      • 是的,这可能是最好的主意,我会稍微收紧一些并尝试设置它以获得更好的错误消息,看看它是否会再次发生。影响不大,我猜他们只需要刷新页面即可。
      【解决方案5】:

      正如其他人所说,比较可能会导致问题。
      是否有任何比较标准包含空值?具体来说,字符串属性?

      即如果 firstname 或 lastname 或 emailId 为 null 并且如果用于比较,则在字典中用于比较时可能会失败。

      编辑:Supervisor 与 StaffMember 和 AdminStaff 类有何关联?
      在代码中,您将两个实例都转换为 StaffMember。我的猜测是,如果 Supervisor 和 StaffMember 类相关,这可能是个问题。

      EDIT2:字典实例的范围是什么?它是否在应用程序级别/会话级别共享?是否有可能多个线程可以尝试从中读取/写入?

      【讨论】:

      • 我会认为 CompareTo 方法会出现在堆栈跟踪中吗?代码已添加到主帖子我明白你的意思,我将添加对姓氏的空值检查,尽管它们不应该为空,它们在构造函数中设置并从设置为“非空”值的 sql 数据库返回/跨度>
      • Supervisor 和 AdminOfficer 都是 StaffMember 的类型。继承树是: Staff Member Supervisor AdminOfficer Staff Member 可以是普通的旧 StaffMember、Supervisor 或 AdminOfficer。除了正常的属性外,主管还有一份受其监管的 StaffMembers 列表。它们像这样分开主要是为了验证目的,当您登录时,您的用户名与 StaffMember 相关联 - 如果它是主管,您可以做一些 StaffMember 不能做的事情,如果您是 AdminOfficer,您可以做更多
      • 这是字符串属性为空的问题吗?您是否添加了空检查?之后是否发生异常?
      • 感谢您的输入 shahkalpesh,我已添加检查,但这是一个不可重现的错误(今天只收到 1 封电子邮件,方法已被调用数千次)。不过,我不相信 firstNames 可以为 null - 它们是直接从数据库中提取的,并且数据库不允许名字为 null 值。
      【解决方案6】:

      我看到的另一种与线程无关的异常是在序列化字典时。在这种情况下,它是空的,但我仍然在反序列化实例的 Insert() 方法中得到 NullReferenceException。

      在我的例子中,简单的改变就是在反序列化后创建一个新实例。我不确定序列化是否只是破坏了 Dictionary,或者它是否是 Dictionary 所定义的类型。

      在我的情况下,如果没有序列化代理(我已经提供了这些),这些类型是不可序列化的,但也许字典中的某些东西在这里有问题。尽管如此,字典还是空的,这仍然发生。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-11-10
        • 2011-02-24
        • 1970-01-01
        • 1970-01-01
        • 2017-03-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多