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:
1) Breakpoint to the if
2) Set the next execution point:
3) Try to continue with 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. Basically, date
is not a variable - it is a field on a capture-context, because of the 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:
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:
ctx.date = new DateTime();
The capture-context line immediately before that, i.e.
var ctx = new SomeCaptureContext();
never got executed, so ctx
is null
. Hence the 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
".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With