【问题标题】:Using Reflection.Emit to emit a "using (x) { ... }" block?使用 Reflection.Emit 发出“使用 (x) { ... }” 块?
【发布时间】:2010-06-08 15:49:25
【问题描述】:

我正在尝试在 C# 中使用 Reflection.Emit 来发出 using (x) { ... } 块。

在代码中,我需要获取堆栈的当前顶部,这是一个实现 IDisposable 的对象,将其存储在局部变量中,在该变量上实现一个 using 块,然后在其中添加更多代码(我可以处理最后一部分。)

这是我尝试在 Reflector 中编译和查看的一段示例 C# 代码:

public void Test()
{
    TestDisposable disposable = new TestDisposable();
    using (disposable)
    {
        throw new Exception("Test");
    }
}

这在 Reflector 中是这样的:

.method public hidebysig instance void Test() cil managed
{
    .maxstack 2
    .locals init (
        [0] class LVK.Reflection.Tests.UsingConstructTests/TestDisposable disposable,
        [1] class LVK.Reflection.Tests.UsingConstructTests/TestDisposable CS$3$0000,
        [2] bool CS$4$0001)
    L_0000: nop 
    L_0001: newobj instance void LVK.Reflection.Tests.UsingConstructTests/TestDisposable::.ctor()
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: stloc.1 
    L_0009: nop 
    L_000a: ldstr "Test"
    L_000f: newobj instance void [mscorlib]System.Exception::.ctor(string)
    L_0014: throw 
    L_0015: ldloc.1 
    L_0016: ldnull 
    L_0017: ceq 
    L_0019: stloc.2 
    L_001a: ldloc.2 
    L_001b: brtrue.s L_0024
    L_001d: ldloc.1 
    L_001e: callvirt instance void [mscorlib]System.IDisposable::Dispose()
    L_0023: nop 
    L_0024: endfinally 
    .try L_0009 to L_0015 finally handler L_0015 to L_0025
}

当使用 Reflection.Emit 时,我不知道如何处理最后的“.try ...”部分。

有人能指出正确的方向吗?


编辑:在通过电子邮件询问代码后,我将在此处发布我的流利界面代码,但除非您获取我的一些类库,否则它对任何人都没有多大用处,这也是一些代码。我正在努力处理的代码是我的 IoC 项目的一部分,我需要生成一个类来实现服务上方法调用的自动记录,基本上是一个用于自动生成代码的服务的装饰器类。

实现所有接口方法的方法的主循环是这样的:

foreach (var method in interfaceType.GetMethods())
{
    ParameterInfo[] methodParameters = method.GetParameters();
    var parameters = string.Join(", ", methodParameters
        .Select((p, index) => p.Name + "={" + index + "}"));
    var signature = method.Name + "(" + parameters + ")";
    type.ImplementInterfaceMethod(method).GetILGenerator()
        // object[] temp = new object[param-count]
        .variable<object[]>() // #0
        .ldc(methodParameters.Length)
        .newarr(typeof(object))
        .stloc_0()
        // copy all parameter values into array
        .EmitFor(Enumerable.Range(0, methodParameters.Length), (il, i) => il
            .ldloc_0()
            .ldc(i)
            .ldarg_opt(i + 1)
            .EmitIf(methodParameters[i].ParameterType.IsValueType, a => a
                .box(methodParameters[i].ParameterType))
            .stelem(typeof(object))
        )
        // var x = _Logger.Scope(LogLevel.Debug, signature, parameterArray)
        .ld_this()
        .ldfld(loggerField)
        .ldc(LogLevel.Debug)
        .ldstr(signature)
        .ldloc(0)
        .call_smart(typeof(ILogger).GetMethod("Scope", new[] { typeof(LogLevel), typeof(string), typeof(object[]) }))
        // using (x) { ... }
        .EmitUsing(u => u
            .ld_this()
            .ldfld(instanceField)
            .ldargs(Enumerable.Range(1, methodParameters.Length).ToArray())
            .call_smart(method)
            .EmitCatch<Exception>((il, ex) => il
                .ld_this()
                .ldfld(loggerField)
                .ldc(LogLevel.Debug)
                .ldloc(ex)
                .call_smart(typeof(ILogger).GetMethod("LogException", new[] { typeof(LogLevel), typeof(Exception) }))
            )
        )
        .ret();
}

EmitUsing 吐出 Jon 回答的 BeginExceptionBlock,所以这就是我需要知道的。

以上代码来自LoggingDecorator.cs,IL扩展大多在ILGeneratorExtensions.Designer.cs,其他文件在LVK.Reflection命名空间。

【问题讨论】:

    标签: c# reflection.emit using-statement ilgenerator


    【解决方案1】:

    ILGenerator.BeginExceptionBlock 是你想要的吗?文档中的示例表明这是正确的方法...

    【讨论】:

    • 是的,这就是我所追求的。谢谢。如果其他人寻找类似的东西,我会发布代码。
    • 再想一想,我会放弃发布我的代码,我有一个广泛的 Reflection.Emit 扩展方法库,所以我必须全部重写,如果有人问我会这样做对于它,但我当前的代码可能对除我之外的任何人都没有帮助。
    【解决方案2】:

    这是一个示例,在代码中。

    ILGenerator ilg = ...;
    
    // Begin the 'try' block. The returned label is at the end of the 'try' block.
    // You can jump there and any finally blocks will be executed.
    Label block = ilg.BeginExceptionBlock();
    
    // ... emit operations that might throw
    
    ilg.BeginFinallyBlock();
    
    // ... emit operations within the finally block
    
    ilg.EndExceptionBlock();
    

    【讨论】:

      猜你喜欢
      • 2011-12-07
      • 2011-01-19
      • 2011-04-08
      • 2013-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多