简体   繁体   English

为什么以下C#代码在可空的DateTime初始化时抛出NullReferenceException?

[英]Why the following C# code throws NullReferenceException on nullable DateTime initialization?

Here's some simple code: 这是一些简单的代码:

    static void Main(string[] args)
    {
        var coll = new List<string> {"test", "test2", "test3"};

        var filteredColl = coll.Select(x => x).ToList();

        if (!filteredColl.Any())
        {
            DateTime? date = new DateTime();

            filteredColl = coll.Where(x => date.GetValueOrDefault().Date.ToString(CultureInfo.InvariantCulture) == x).Select(x => x).ToList();
        }
    }

The question is, why the following steps make it crash with NullReferenceException : 问题是, 为什么以下步骤使其与NullReferenceException崩溃

1) Breakpoint to the if 1)断点到if

断点

2) Set the next execution point: 2)设置下一个执行点:

执行点

3) Try to continue with F10: 3)尝试继续使用F10:

例外

If I comment out the last line of the code, it won't crash. 如果我注释掉代码的最后一行,它就不会崩溃。

Update: Here's the stack trace: 更新:这是堆栈跟踪:

System.NullReferenceException was unhandled   HResult=-2147467261  
Message=Object reference not set to an instance of an object.  
Source=ConsoleApplication28   StackTrace:
       at ConsoleApplication28.Program.Main(String[] args) in Program.cs: line 21
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()   InnerException:

This is a side-effect of moving the execution point inside a context that declares a captured variable scope. 这是在声明捕获的变量范围的上下文中移动执行点的副作用。 It would be reasonable to report it as an IDE bug, but it would not be trivial to fix. 将其报告为IDE错误是合理的,但修复并不是一件容易的事。 Basically, date is not a variable - it is a field on a capture-context, because of the lambda. 基本上, date不是变量 - 它是捕获上下文中的字段 ,因为lambda。 The compiler essentially does: 编译器基本上做:

if (!filteredColl.Any())
{
    var ctx = new SomeCaptureContext(); // <== invented by the compiler
    ctx.date = new DateTime();

    filteredColl = coll.Where(ctx.SomePredicate).Select(x => x).ToList();
}

where SomePredicate is: SomePredicate是:

class SomeCaptureContext {
    public DateTime? date; // yes, a public field - needs to support 'ref' etc
    public bool SomePredicate(string x) // the actual name is horrible
    {
        return this.date.GetValueOrDefault()
              .Date.ToString(CultureInfo.InvariantCulture) == x;
    }
}

The problem here is that when you drag the execution position to: 这里的问题是当您将执行位置拖动到:

DateTime? date = new DateTime();

You are actually (in IL terms) dragging it to the line: 实际上 (以IL术语)将其拖动到该行:

ctx.date = new DateTime();

The capture-context line immediately before that, ie 紧接着之前的捕获上下文行,即

var ctx = new SomeCaptureContext();

never got executed, so ctx is null . 从未执行过,所以ctxnull Hence the NullReferenceException . 因此NullReferenceException

It would be reasonable to log this as a bug, but it is a subtle one - and you wouldn't necessarily always want dragging the execution context to initialize the capture-contexts - it would have to be "if they are null ". 将此作为一个错误记录是合理的,但它是一个微妙的 - 你不一定总是想要拖动执行上下文来初始化捕获上下文 - 它必须是“如果它们为null ”。

Hmm... Really it looks weird. 嗯......真的很奇怪。 Do you have mscorlib in references and System in usings? 你有引用中的mscorlib和使用中的系统吗? Maybe you have some another class named DateTime and it overrides System.DateTime. 也许你有一个名为DateTime的另一个类,它会覆盖System.DateTime。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM