This question already has an answer here:
CLR System.NullReferenceException when forcing 'Set Next Statement' into 'if' block
(1个答案)
5年前关闭。
为什么这会增加?
拖动执行光标时,存在损坏调用堆栈的风险。这是因为拖动光标实际上会跳过这些行。在调试器中运行时,在按F10键之后,光标将在尝试之前停在
这将创建
因为您跳过了它,所以没有创建该对象,因此在运行时会得到一个
我不确定为什么人们无法在VS2012上重现此内容。也许编译器输出的是不同的IL,但这距离我可以使用VS2013 Ultimate和C#4.5的距离还远。
有趣的是,当您注释掉try/catch时,IL中程序的启动看起来像这样:
您可以在例程的第一行看到它创建了
编辑
深入研究,将程序更改为此:
产生工作代码。检查IL,您可以看到实例创建已移至try之外:
编译器足够好,可以将字符串数组的创建从try外部移到try内部,因此跳过该行仍会生成有效对象。该代码有效,因此我猜测
(1个答案)
5年前关闭。
为什么这会增加?
using System;
using System.Linq;
namespace Test
{
internal class Program
{
private static void Main(string[] args)
{
try
{
// 1. Hit F10 to step into debugging.
string[] one = {"1"}; //2. Drag arrow to make this next statement executed
// 3. Hit f5.
Enumerable.Range(1,1)
.Where(x => one.Contains(x.ToString()));
}
catch (Exception exception)
{
Console.Write("BOOM!");
}
}
}
}
最佳答案
查看ILDASM输出,这里可能会有解释...
.locals init ([0] class Test.Program/'<>c__DisplayClass1' 'CS$<>8__locals2',
[1] class [mscorlib]System.Exception exception,
[2] string[] CS$0$0000)
IL_0000: nop
.try
{
IL_0001: newobj instance void Test.Program/'<>c__DisplayClass1'::.ctor()
IL_0006: stloc.0
IL_0007: nop
IL_0008: ldloc.0
IL_0009: ldc.i4.1
IL_000a: newarr [mscorlib]System.String
IL_000f: stloc.2
IL_0010: ldloc.2
IL_0011: ldc.i4.0
IL_0012: ldstr "1"
IL_0017: stelem.ref
IL_0018: ldloc.2
IL_0019: stfld string[] Test.Program/'<>c__DisplayClass1'::one
IL_001e: ldc.i4.1
IL_001f: ldc.i4.1
IL_0020: call class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> [System.Core]System.Linq.Enumerable::Range(int32,
int32)
IL_0025: ldloc.0
IL_0026: ldftn instance bool Test.Program/'<>c__DisplayClass1'::'<Main>b__0'(int32)
IL_002c: newobj instance void class [mscorlib]System.Func`2<int32,bool>::.ctor(object,
native int)
IL_0031: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<int32>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>,
class [mscorlib]System.Func`2<!!0,bool>)
IL_0036: pop
IL_0037: nop
IL_0038: leave.s IL_004a
} // end .try
catch [mscorlib]System.Exception
{
拖动执行光标时,存在损坏调用堆栈的风险。这是因为拖动光标实际上会跳过这些行。在调试器中运行时,在按F10键之后,光标将在尝试之前停在
Main
例程的开头。如果将光标拖动到数组的创建上,那么您将跳过以下有趣的行:IL_0001: newobj instance void Test.Program/'<>c__DisplayClass1'::.ctor()
这将创建
Program
类的实例。该程序类随后将在此处使用:IL_0019: stfld string[] Test.Program/'<>c__DisplayClass1'::one
因为您跳过了它,所以没有创建该对象,因此在运行时会得到一个
NullReferenceException
。我不确定为什么人们无法在VS2012上重现此内容。也许编译器输出的是不同的IL,但这距离我可以使用VS2013 Ultimate和C#4.5的距离还远。
有趣的是,当您注释掉try/catch时,IL中程序的启动看起来像这样:
.locals init ([0] class Test.Program/'<>c__DisplayClass1' 'CS$<>8__locals2',
[1] string[] CS$0$0000)
IL_0000: newobj instance void Test.Program/'<>c__DisplayClass1'::.ctor()
IL_0005: stloc.0
您可以在例程的第一行看到它创建了
Program
对象。为什么编译器决定将该行放入try/catch中,这超出了我的范围。编辑
深入研究,将程序更改为此:
private static void Main(string[] args)
{
string[] one;
try
{
// 1. Hit F10 to step into debugging.
one = new string[] { "1" }; //2. Drag arrow to this
// 3. Hit f5.
Enumerable.Range(1, 1)
.Where(x => one.Contains(x.ToString()));
}
catch (Exception exception)
{
Console.Write("BOOM!");
}
}
产生工作代码。检查IL,您可以看到实例创建已移至try之外:
.locals init ([0] class [mscorlib]System.Exception exception,
[1] class [mscorlib]System.Func`2<int32,bool> 'CS$<>9__CachedAnonymousMethodDelegate1',
[2] class Test.Program/'<>c__DisplayClass2' 'CS$<>8__locals3',
[3] string[] CS$0$0000)
IL_0000: ldnull
IL_0001: stloc.1
IL_0002: newobj instance void Test.Program/'<>c__DisplayClass2'::.ctor()
IL_0007: stloc.2
IL_0008: nop
.try
{
编译器足够好,可以将字符串数组的创建从try外部移到try内部,因此跳过该行仍会生成有效对象。该代码有效,因此我猜测
NullReferenceException
确实是Program
类的实例。关于c# - 在Visual Studio中更改下一行执行时的意外后果,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30808551/
10-13 08:22