C# 我是如何在构造函数之后立即得到这个 NullReferenceException 错误的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1320264/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 15:06:32  来源:igfitidea点击:

How did I get this NullReferenceException error here right after the constructor?

c#asp.netnullreferenceexception

提问by RodH257

I've had an asp.net website running live on our intranet for a couple of weeks now. I just got an email from my application_error emailer method with an unhandled exception.

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

Here it is (I've cleaned up some of the paths to make it better displayed)

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

Exception : Object reference not set to an instance of an object. Stack Trace : at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value) at TimesheetDomain.DataMappers.StaffMemberData.ReadStaff(SqlDataReader reader) in TimesheetDomain\DataMappers\StaffMemberData.cs:line 362

at TimesheetDomain.DataMappers.StaffMemberData.GetStaffMember(String name) in TimesheetDomain\DataMappers\StaffMemberData.cs:line 401

at TimesheetDomain.ServiceLayer.TimesheetManager.GetUserFromName(String name) in TimesheetDomain\ServiceLayer\TimesheetManager.cs:line 199

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

at System.Web.UI.Control.InitRecursive(Control namingContainer) at System.Web.UI.Control.InitRecursive(Control namingContainer) at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

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

在 TimesheetDomain.DataMappers.StaffMemberData.GetStaffMember(String name) in TimesheetDomain\DataMappers\StaffMemberData.cs:line 401

在 TimesheetDomain.ServiceLayer.TimesheetManager.GetUserFromName(String name) in TimesheetDomain\ServiceLayer\TimesheetManager.cs:line 199

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

在 System.Web.UI.Control.InitRecursive(Control NamingContainer) 在 System.Web.UI.Control.InitRecursive(Control NamingContainer) 在 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

Basically it looks like it's erroring at my ReadStaff method which reads a data reader to build staff member objects. Here is the bit of code:

基本上看起来它在我的 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;
}

(Line 362 is 3rd last line) I'm using an identity map (just read fowlers book on patterns and thought it was a good idea - may have done it wrong, happy for comments) but that's not overly relevant as later on I use the newMemberobject elsewhere so if I remove that block the NullReferenceExceptionwill occur.

(第 362 行是倒数第 3 行)我正在使用身份映射(只是阅读了有关模式的 fowlers 书并认为这是一个好主意 - 可能做错了,很高兴发表评论)但这并不太相关,因为我稍后会使用newMember其他地方的对象,所以如果我删除那个块,NullReferenceException就会发生。

I am struggling to see how on earth newMemberis null in the 3rd last line there (which is the line that errored).

我正在努力了解在newMember那里的最后一行(这是出错的行)中到底是如何为空的。

Resharper/VS doesn't give me a warning that it could be null- because there's the 3 constructors which I choose from.

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

Can anyone suggest where I can look to try and fix this error? It's only happened once and that method has been called thousands of times since the site went live.

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

Thanks

谢谢

[EDIT] As Requested, here's the IComparer for staff member

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

and it's used in the IComparable implementation

它用于 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);
}

采纳答案by McKenzieG1

It is almost certainly a threading issue - see this question and its accepted answer.

这几乎可以肯定是一个线程问题 - 请参阅此问题及其已接受的答案

Dictionary<>.Insert()will throw a NullReferenceExceptioninternally if the dictionary instance is modified from another thread during the insert operation.

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

回答by shahkalpesh

As others have said, the comparison could be causing the problem.
Is any of the criteria for comparison contain null value? specifically, the string properties?

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

i.e. If firstname or lastname or emailId is null and if it is used in comparison, things could fail when used inside the dictionary for comparison.

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

EDIT: How is Supervisor and StaffMember and AdminStaff class related?
In the code, you are casting both the instances to StaffMember. My guess is that it could be a problem if the Supervisor and StaffMember class are notrelated.

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

EDIT2: What is the scrope of the dictionary instance? Is it shared at application level/session level? Is it possible that multiple threads could try to read/write from it?

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

回答by rism

I can't see anything obvious. I'd run some SQL to check the database for any bad data. The problem may be a freak bug in a related input form. If the code has been run thousands of times without incident until now, i'd wrap some additional exception handling/reporting around the code block in question so you can at least get a staffId if/when it next happens.

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

You could burn a lot of time on something like this. The most expedient approach may be just to let it fail again under the above/controlled conditions..... assuming the level of disruption it causes is acceptable/manageable/minor.

你可以在这样的事情上消耗很多时间。最方便的方法可能只是让它在上述/受控条件下再次失败......假设它造成的破坏程度是可以接受的/可管理的/轻微的。

I appreciate that wont satisfy the immediate need to know but it may be the best way to manage the problem especially with such a low failure rate.

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

回答by Akash Kava

It's only happened once and that method has been called thousands of times since the site went live.

它只发生过一次,而且自从网站上线以来,这个方法已经被调用了数千次。

After reading this, I can conclude that, its possible that .NET may have exhausted its memory and it could not create any more Dictionary key, it may not really be anywhere your fault. But yes we did get these kind of errors when we tried to store too much information in session/application variables thus increasing memory footprint of the Web Application. But we got such errors when our numbers went really high, like storing 10,000 items in Dictionary or List etc.

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

The pattern is good, but you must also realize that we use database to store information in relational format, if we start using memory to store similar things, then we are ignoring powerful database. Database can cache values for you as well.

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

It might sound silly but we have our windows server restart in every 24 hours, at midnight when there is no traffic. That did help us in getting rid of such errors. We restart our servers regularly at a fix schedule in order to get all the cache/logs cleared.

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

回答by Todd

Another way I have seen this exception, unrelated to threading, is when serializing a Dictionary. In this case, it was empty, but I still got the NullReferenceException in the Insert() method on the deserialized instance.

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

The simple change in my case was just to create a new instance after deserialization. I'm not sure whether the serialization just breaks the Dictionary, or if it is the types that the Dictionary is defined for.

在我的情况下,简单的更改只是在反序列化后创建一个新实例。我不确定序列化是否只是破坏了字典,或者它是否是为字典定义的类型。

In my case the types were not serializable without serialization surrogates (and I had provided these), but maybe something in the Dictionary had a problem here. Again though, the Dictionary was empty and this still happened.

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

回答by Bill Noto

As of .NET 4.0 you can use ConcurrentDictionary and avoid the threading issues associated with manipulating the same dictionary from multiple threads simultaneously.

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