static void Test() { int[] aa = null; foreach (int x in aa) { int y = x; } }ildasm
.method private hidebysig static void Test() cil managed { // Code size 40 (0x28) .maxstack 2 .locals init ([0] int32[] aa, [1] int32 x, [2] int32 y, [3] int32[] CS$6$0000, [4] int32 CS$7$0001, [5] bool CS$4$0002) IL_0000: nop IL_0001: ldnull IL_0002: stloc.0 IL_0003: nop IL_0004: ldloc.0 IL_0005: stloc.3 IL_0006: ldc.i4.0 IL_0007: stloc.s CS$7$0001 IL_0009: br.s IL_001a IL_000b: ldloc.3 IL_000c: ldloc.s CS$7$0001 IL_000e: ldelem.i4 IL_000f: stloc.1 IL_0010: nop IL_0011: ldloc.1 IL_0012: stloc.2 IL_0013: nop IL_0014: ldloc.s CS$7$0001 IL_0016: ldc.i4.1 IL_0017: add IL_0018: stloc.s CS$7$0001 IL_001a: ldloc.s CS$7$0001 IL_001c: ldloc.3 IL_001d: ldlen IL_001e: conv.i4 IL_001f: clt IL_0021: stloc.s CS$4$0002 IL_0023: ldloc.s CS$4$0002 IL_0025: brtrue.s IL_000b IL_0027: ret } // end of method OleDbTest::Test(2) With a queue - uses try
static void Test1() { Queue q = null; foreach (object x in q) { object y = x; } }ildasm
.method private hidebysig static void Test1() cil managed { // Code size 68 (0x44) .maxstack 2 .locals init ([0] class [mscorlib]System.Collections.Queue q, [1] object x, [2] object y, [3] class [mscorlib]System.Collections.IEnumerator CS$5$0000, [4] bool CS$4$0001, [5] class [mscorlib]System.IDisposable CS$0$0002) IL_0000: nop IL_0001: ldnull IL_0002: stloc.0 IL_0003: nop IL_0004: ldloc.0 IL_0005: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.Queue::GetEnumerator() IL_000a: stloc.3 .try { IL_000b: br.s IL_0018 IL_000d: ldloc.3 IL_000e: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current() IL_0013: stloc.1 IL_0014: nop IL_0015: ldloc.1 IL_0016: stloc.2 IL_0017: nop IL_0018: ldloc.3 IL_0019: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() IL_001e: stloc.s CS$4$0001 IL_0020: ldloc.s CS$4$0001 IL_0022: brtrue.s IL_000d IL_0024: leave.s IL_0042 } // end .try finally { IL_0026: ldloc.3 IL_0027: isinst [mscorlib]System.IDisposable IL_002c: stloc.s CS$0$0002 IL_002e: ldloc.s CS$0$0002 IL_0030: ldnull IL_0031: ceq IL_0033: stloc.s CS$4$0001 IL_0035: ldloc.s CS$4$0001 IL_0037: brtrue.s IL_0041 IL_0039: ldloc.s CS$0$0002 IL_003b: callvirt instance void [mscorlib]System.IDisposable::Dispose() IL_0040: nop IL_0041: endfinally } // end handler IL_0042: nop IL_0043: ret } // end of method OleDbTest::Test1(3) With a Queue < T > - uses Try
static void Test2() { Queue<int> q = null; foreach (int x in q) { int y = x; } }ildasm
.method private hidebysig static void Test2() cil managed { // Code size 57 (0x39) .maxstack 1 .locals init ([0] class [System]System.Collections.Generic.Queue`1<int32> q, [1] int32 x, [2] int32 y, [3] valuetype [System]System.Collections.Generic.Queue`1/Enumerator<int32> CS$5$0000, [4] bool CS$4$0001) IL_0000: nop IL_0001: ldnull IL_0002: stloc.0 IL_0003: nop IL_0004: ldloc.0 IL_0005: callvirt instance valuetype [System]System.Collections.Generic.Queue`1/Enumerator<!0> class [System]System.Collections.Generic.Queue`1<int32>::GetEnumerator() IL_000a: stloc.3 .try { IL_000b: br.s IL_0019 IL_000d: ldloca.s CS$5$0000 IL_000f: call instance !0 valuetype [System]System.Collections.Generic.Queue`1/Enumerator<int32>::get_Current() IL_0014: stloc.1 IL_0015: nop IL_0016: ldloc.1 IL_0017: stloc.2 IL_0018: nop IL_0019: ldloca.s CS$5$0000 IL_001b: call instance bool valuetype [System]System.Collections.Generic.Queue`1/Enumerator<int32>::MoveNext() IL_0020: stloc.s CS$4$0001 IL_0022: ldloc.s CS$4$0001 IL_0024: brtrue.s IL_000d IL_0026: leave.s IL_0037 } // end .try finally { IL_0028: ldloca.s CS$5$0000 IL_002a: constrained. valuetype [System]System.Collections.Generic.Queue`1/Enumerator<int32> IL_0030: callvirt instance void [mscorlib]System.IDisposable::Dispose() IL_0035: nop IL_0036: endfinally } // end handler IL_0037: nop IL_0038: ret } // end of method OleDbTest::Test2>Also I wonder if it would make sense to have an alternate 'light-weight' exception that didn't build up the stack trace info.....