C# 为什么ILGenerator在Foreach语句中插入LEVE指令
我生成以下代码:C# 为什么ILGenerator在Foreach语句中插入LEVE指令,c#,cil,reflection.emit,il,ilgenerator,C#,Cil,Reflection.emit,Il,Ilgenerator,我生成以下代码: public override void Map(IEnumerable enumerable1) { List<int> list = new List<int>(); foreach (object obj2 in enumerable1) { } } 以下是结果IL(请参见IL001f): .method公共虚拟实例无效映射(类[mscorlib]System.Collections.IEnumerable A_1
public override void Map(IEnumerable enumerable1)
{
List<int> list = new List<int>();
foreach (object obj2 in enumerable1)
{
}
}
以下是结果IL(请参见IL001f
):
.method公共虚拟实例无效映射(类[mscorlib]System.Collections.IEnumerable A_1)cil托管
{
//代码大小54(0x36)
.maxstack 5
.locals init(类[mscorlib]System.Collections.Generic.List`1 V_0,
对象V_1,
类[mscorlib]System.Collections.IEnumerator V_2,
类[mscorlib]System.IDisposable V_3)
IL_0000:newobj实例无效类[mscorlib]System.Collections.Generic.List`1::.ctor()
IL_0005:stloc.0
IL_0006:ldarg.1
IL_0007:callvirt实例类[mscorlib]System.Collections.IEnumerator[mscorlib]System.Collections.IEnumerable::GetEnumerator()
IL_000c:stloc.2
尝试
{
IL_000d:br.s IL_0017
IL_000f:ldloc.2
IL_0010:callvirt实例对象[mscorlib]System.Collections.IEnumerator::get_Current()
IL_0015:stloc.1
IL_0016:ldloc.1
IL_0017:ldloc.2
IL_0018:callvirt实例bool[mscorlib]System.Collections.IEnumerator::MoveNext()
IL_001d:brtrue.s IL_000f
问题就在这里
IL_001f:离开IL_0035
}//结束,再试一次
最后
{
IL_0024:ldloc.2
IL_0025:isinst[mscorlib]System.IDisposable
IL_002a:stloc.3
IL_002b:ldloc.3
IL_002c:brfalse.s IL_0034
IL_002e:ldloc.3
IL_002f:callvirt实例void[mscorlib]System.IDisposable::Dispose()
IL_0034:最终结束
}//结束处理程序
IL_0035:ret
}//方法ForeachType::Map的结尾
请您澄清一下为什么会出现“离开”指令?谢谢您的建议。下面解释发生了什么
public virtual void BeginFinallyBlock()
{
if (m_currExcStackCount==0) {
throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock"));
}
__ExceptionInfo current = m_currExcStack[m_currExcStackCount-1];
int state = current.GetCurrentState();
Label endLabel = current.GetEndLabel();
int catchEndAddr = 0;
if (state != __ExceptionInfo.State_Try)
{
// generate leave for any preceeding catch clause
this.Emit(OpCodes.Leave, endLabel);
catchEndAddr = m_length;
}
MarkLabel(endLabel);
Label finallyEndLabel = this.DefineLabel();
current.SetFinallyEndLabel(finallyEndLabel);
// generate leave for try clause
this.Emit(OpCodes.Leave, finallyEndLabel); HERE'S THE ANSWER
if (catchEndAddr == 0)
catchEndAddr = m_length;
current.MarkFinallyAddr(m_length, catchEndAddr);
}
我相信这是终止任何
try{}
块的IL要求。也许,但同样的手写代码有leave.s
指令。如果我插入leave.s
有两条说明我不确定我是否完全理解你在这里说的话,但是leave
和leave.s
是相同的说明,除了目标标签的允许范围。是的,相同,我没有插入leave
说明。真奇怪。为什么相同的代码有不同的指令?手写的有leave.s和我的代码leave。只要看一看,它就很明显是从哪里来的。嗯,你能解释一下吗,对我来说,代码是正确的,但注释不是:)实际上是这个方法中的低代码块被注释了//generate leave for try子句
,它添加了您正在寻找的假期-正如Ben指出的,代码中缺少catch
子句意味着这个块,已注释的//为任何前面的catch子句生成休假
是不相关的。
.method public virtual instance void Map(class [mscorlib]System.Collections.IEnumerable A_1) cil managed
{
// Code size 54 (0x36)
.maxstack 5
.locals init (class [mscorlib]System.Collections.Generic.List`1<int32> V_0,
object V_1,
class [mscorlib]System.Collections.IEnumerator V_2,
class [mscorlib]System.IDisposable V_3)
IL_0000: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
IL_0005: stloc.0
IL_0006: ldarg.1
IL_0007: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator()
IL_000c: stloc.2
.try
{
IL_000d: br.s IL_0017
IL_000f: ldloc.2
IL_0010: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
IL_0015: stloc.1
IL_0016: ldloc.1
IL_0017: ldloc.2
IL_0018: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_001d: brtrue.s IL_000f
THE ISSUE IS HERE
IL_001f: leave IL_0035
} // end .try
finally
{
IL_0024: ldloc.2
IL_0025: isinst [mscorlib]System.IDisposable
IL_002a: stloc.3
IL_002b: ldloc.3
IL_002c: brfalse.s IL_0034
IL_002e: ldloc.3
IL_002f: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0034: endfinally
} // end handler
IL_0035: ret
} // end of method ForeachType::Map
public virtual void BeginFinallyBlock()
{
if (m_currExcStackCount==0) {
throw new NotSupportedException(Environment.GetResourceString("Argument_NotInExceptionBlock"));
}
__ExceptionInfo current = m_currExcStack[m_currExcStackCount-1];
int state = current.GetCurrentState();
Label endLabel = current.GetEndLabel();
int catchEndAddr = 0;
if (state != __ExceptionInfo.State_Try)
{
// generate leave for any preceeding catch clause
this.Emit(OpCodes.Leave, endLabel);
catchEndAddr = m_length;
}
MarkLabel(endLabel);
Label finallyEndLabel = this.DefineLabel();
current.SetFinallyEndLabel(finallyEndLabel);
// generate leave for try clause
this.Emit(OpCodes.Leave, finallyEndLabel); HERE'S THE ANSWER
if (catchEndAddr == 0)
catchEndAddr = m_length;
current.MarkFinallyAddr(m_length, catchEndAddr);
}