我試圖在C#中使用Reflection.Emit來發出using (x) { ... }
塊。使用Reflection.Emit發出「使用(x){...}」塊?
在代碼中,我需要獲取堆棧的當前頂部,它是一個實現IDisposable的對象,將其存儲在局部變量中,在該變量上實現一個使用塊,然後放入它添加更多的代碼
下面是一個示例C#代碼片段我試圖編譯和反射看看(我能處理半句。):
public void Test()
{
TestDisposable disposable = new TestDisposable();
using (disposable)
{
throw new Exception("Test");
}
}
這看起來像這樣在反射器:
.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吐出喬恩回答與BeginExceptionBlock,所以這就是我需要知道的東西。
上面的代碼是從LoggingDecorator.cs開始的,IL擴展名主要是ILGeneratorExtensions.Designer.cs,其他文件位於LVK.Reflection命名空間。
是的,這是我以後的事情。謝謝。如果其他人尋找類似的東西,我會發布代碼。 – 2010-06-08 16:13:45
關於第二個想法,我將放棄發佈我的代碼,我有一個用於Reflection.Emit的擴展方法的擴展庫,所以我將不得不重寫它,如果有人要求,我會這樣做,但是我當前的代碼可能對除我以外的任何人都有幫助。 – 2010-06-08 16:16:15