-> Start debug mode -> Reach if(calculate)
line -> Drag arrow to next line {
-> Reach string sValue = "ABC123";
-> Threw an exception Object reference not set to an instance of an object.
But if i set calculate = true and don't drag arrow and just continue with F10 there is no exception at all. You can see in code, 5 cases when throw exception and when not throw exception. When i define sValue before if block, there is no exception.
Can you explain why throw exception in this situation ?
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
public static List<SaleLineItem> SaleItems = new List<SaleLineItem>();
static void Main(string[] args)
{
SaleItems.Add(new SaleLineItem { ItemId = "ABC123", NetAmount = 2 });
SaleItems.Add(new SaleLineItem { ItemId = "ABC123", NetAmount = 3 });
try
{
bool calculate = false;
// string sValue = "ABC123";
if (calculate)
{
string sValue = "ABC123";
decimal total = 0;
#region Exception
total = SaleItems.Where(t => t.ItemId != sValue).Count();
// total = SaleItems.Where(t => t.ItemId != sValue).Sum(t => t.NetAmountWithTax);
// var newSaleItems = SaleItems.FirstOrDefault(t => t.ItemId != sValue);
#endregion
#region No Exception
// string newValue = sValue;
// var newSaleItems = SaleItems.FirstOrDefault();
#endregion
}
}
catch (Exception ex)
{
throw ex;
}
}
}
[Serializable]
public class SaleLineItem
{
public string ItemId { get; set; }
public decimal NetAmount { get; set; }
}
}
I might have found a reason why that happens.
First of all I beoke down your code to see what it needs to get that Exception and ended up like this:
List<string> SaleItems = new List<string>();
var test = false;
if(test)
{
var sValue = "ABC123";
SaleItems.Count(t => t != sValue);
}
This produces the exact same error, as you described.
So my guess was this could be a problem with the compiler that optimized something, so I took a look at the Intermediate Language (IL) produced by this code. Here's the part that I think is interesting: (Note: The lines starting with // are just comments for visualisation to which part of the code the comments belong)
//000013:
//000014: if(test)
IL_0009: ldloc.1
IL_000a: stloc.2
//000015: {
//000016: var sValue = "ABC123";
//000017:
//000018: SaleItems.Count(t => t != sValue);
//000019: }
//000020: }
//000021: }
//000022: }
IL_000b: ldloc.2
IL_000c: brfalse.s IL_0034
IL_000e: newobj instance void TestConsoleApplciation_delete_.Program/'<>c__DisplayClass0_0'::.ctor()
IL_0013: stloc.3
//000015: {
IL_0014: nop
//000016: var sValue = "ABC123";
IL_0015: ldloc.3
IL_0016: ldstr "ABC123"
The breakpoint is set at the if(test)
in Line 14, which is in IL the line that starts with IL_0009:
. Now, if you drag the debugger to the next line (Line 15), it will internally jump to the line IL_0014:
and continue from there, so the lines between are skipped.
The problem there is now that the next command that is executed is ldloc.3
at line IL_0015:
(ignoring the nop command, which does nothing) and this command tries to load the variable that is stored at line IL_0013:
but that command was not executed, so it throws the NullReferenceException
because there is nothing to load.
Note: I do not now if this is the real reason why the Exception is thrown but I think it is a pretty reasonable guess.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.