1

I've been trying all day long getting a valid overload for the System.Object.Finalizer()-method. I need to inject a finalizer (if there is not already one) into random classes. The method itself should work just fine - at least reflected it looks valid and I can't see any CIL issues/errors.

This is the code that creates the overloaded method:

destructor = new MethodDefinition("Finalize",
MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.Virtual |
MethodAttributes.ReuseSlot, module.Import(typeof (void)));

baseType.Methods.Add(destructor);

All solutions I found on the internet (which all are rather outdated obviously) only show that you have to set those attributes - nothing more.

This is the compiler-generated version:

.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
}

The following CIL code is my generated code. The most obvious mistake and probably the reason why it does not work is the missing ".override". I can't figure out how I achieve this. I tried about everything possible and it just doesn't work.

.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()
}

So how does this work? When I switch to C# reflection the code looks perfectly fine. It even says "protected override Finalize()" but PEVerify states "bad headers" and the app does not even start with an error message.

SharpShade
  • 1,761
  • 2
  • 32
  • 45
  • http://stackoverflow.com/questions/8102041/how-to-create-an-override-method-using-mono-cecil this? – usr Aug 06 '15 at 22:55
  • Yes. Like I said: Pretty much outdated obviously (2011). At least it does not work for me to just set those few attributes... – SharpShade Aug 07 '15 at 00:07

1 Answers1

0

The solution is (thanks to Jb Evain) simple as that:

Add a TypeReference to the Overrides property of the finalizer method. Obviously this should happen automatically when HideBySig, Virtual and ReuseSlot is being used. Else just manually add the reference.

destructor.Overrides.Add(someModule.Import(typeof(object).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance)));
SharpShade
  • 1,761
  • 2
  • 32
  • 45