C#/Cecil 创建终结器重载
C#/Cecil Creating Finalizer overload
我整天都在尝试为 System.Object.Finalizer() 方法获取有效的重载。我需要向随机 类 中注入一个终结器(如果还没有的话)。该方法本身应该可以正常工作-至少反映出它看起来有效并且我看不到任何 CIL issues/errors.
这是创建重载方法的代码:
destructor = new MethodDefinition("Finalize",
MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.Virtual |
MethodAttributes.ReuseSlot, module.Import(typeof (void)));
baseType.Methods.Add(destructor);
我在互联网上找到的所有解决方案(显然都已经过时了)仅表明您必须设置这些属性 - 仅此而已。
这是编译器生成的版本:
.method family hidebysig virtual instance void Finalize() cil managed
{
.override object::Finalize
.maxstack 2
L_0000: nop
L_0001: nop
L_0002: ldarg.0
L_0003: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
L_0008: ldarg.0
L_0009: ldfld class [App]App.Instancing.InstanceId App.Lab.Wpf.MainWindow::_instance
L_000e: call bool [App]App.Spy::UnsetToken(class [mscorlib]System.Type, class [App]App.Instancing.InstanceId)
L_0013: pop
L_0014: leave.s L_001e
L_0016: ldarg.0
L_0017: call instance void [mscorlib]System.Object::Finalize()
L_001c: nop
L_001d: endfinally
L_001e: ret
.try L_0001 to L_0016 finally handler L_0016 to L_001e
}
以下CIL代码是我生成的代码。最明显的错误以及它不起作用的原因可能是缺少“.override”。我不知道我是如何做到这一点的。我尝试了所有可能的方法,但还是行不通。
.method family hidebysig virtual instance void Finalize() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
L_0006: ldarg.0
L_0007: ldfld class [App]App.Instancing.InstanceId App.Lab.Forms.MainWindow::vbbgsMtrInsVr0221
L_000c: call bool [App]App.Spy::UnsetToken(class [mscorlib]System.Type, class [App]App.Instancing.InstanceId)
L_0011: pop
L_0012: ldarg.0
L_0013: call instance void [mscorlib]System.Object::Finalize()
}
那么这是如何工作的呢?当我切换到 C# 反射时,代码看起来非常好。它甚至说 "protected override Finalize()" 但 PEVerify 指出 "bad headers" 并且该应用程序甚至没有以错误消息开始。
解决方案(感谢 Jb Evain)就这么简单:
在终结器方法的Overrides
属性中添加一个TypeReference
。显然,当使用 HideBySig、Virtual 和 ReuseSlot 时,这应该会自动发生。否则只需手动添加引用。
destructor.Overrides.Add(someModule.Import(typeof(object).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance)));
我整天都在尝试为 System.Object.Finalizer() 方法获取有效的重载。我需要向随机 类 中注入一个终结器(如果还没有的话)。该方法本身应该可以正常工作-至少反映出它看起来有效并且我看不到任何 CIL issues/errors.
这是创建重载方法的代码:
destructor = new MethodDefinition("Finalize",
MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.Virtual |
MethodAttributes.ReuseSlot, module.Import(typeof (void)));
baseType.Methods.Add(destructor);
我在互联网上找到的所有解决方案(显然都已经过时了)仅表明您必须设置这些属性 - 仅此而已。
这是编译器生成的版本:
.method family hidebysig virtual instance void Finalize() cil managed
{
.override object::Finalize
.maxstack 2
L_0000: nop
L_0001: nop
L_0002: ldarg.0
L_0003: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
L_0008: ldarg.0
L_0009: ldfld class [App]App.Instancing.InstanceId App.Lab.Wpf.MainWindow::_instance
L_000e: call bool [App]App.Spy::UnsetToken(class [mscorlib]System.Type, class [App]App.Instancing.InstanceId)
L_0013: pop
L_0014: leave.s L_001e
L_0016: ldarg.0
L_0017: call instance void [mscorlib]System.Object::Finalize()
L_001c: nop
L_001d: endfinally
L_001e: ret
.try L_0001 to L_0016 finally handler L_0016 to L_001e
}
以下CIL代码是我生成的代码。最明显的错误以及它不起作用的原因可能是缺少“.override”。我不知道我是如何做到这一点的。我尝试了所有可能的方法,但还是行不通。
.method family hidebysig virtual instance void Finalize() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
L_0006: ldarg.0
L_0007: ldfld class [App]App.Instancing.InstanceId App.Lab.Forms.MainWindow::vbbgsMtrInsVr0221
L_000c: call bool [App]App.Spy::UnsetToken(class [mscorlib]System.Type, class [App]App.Instancing.InstanceId)
L_0011: pop
L_0012: ldarg.0
L_0013: call instance void [mscorlib]System.Object::Finalize()
}
那么这是如何工作的呢?当我切换到 C# 反射时,代码看起来非常好。它甚至说 "protected override Finalize()" 但 PEVerify 指出 "bad headers" 并且该应用程序甚至没有以错误消息开始。
解决方案(感谢 Jb Evain)就这么简单:
在终结器方法的Overrides
属性中添加一个TypeReference
。显然,当使用 HideBySig、Virtual 和 ReuseSlot 时,这应该会自动发生。否则只需手动添加引用。
destructor.Overrides.Add(someModule.Import(typeof(object).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance)));