2

So I have a simple class reside in my assembly:

public class MyCalculator
  {
    public int Sum(params int[] nums)
    {
      Console.WriteLine("Summing");
      return nums.Sum();
    }
  }

The first thing to know about is that the Sum method is not virtual. I don't want this limitation.
I want to 'override' the Sum method to inject some code in runtime. (Just like any dynamic proxy framework do it. /for example: Castle/)
I created a dummy method (just the relevant parts):

MethodBuilder sumBuilder = myCalculatorProxyType.DefineMethod(myCalculatorSum.Name,
        MethodAttributes.Public |
        MethodAttributes.ReuseSlot |
        MethodAttributes.HideBySig |
        MethodAttributes.SpecialName |
        MethodAttributes.Virtual |
        MethodAttributes.Final,
        CallingConventions.Standard, 
        myCalculatorSum.ReturnType, 
        myCalculatorSum.GetParameters().Select(pi => pi.ParameterType).ToArray());

In the end I try to "override" it with:

myCalculatorProxyType.DefineMethodOverride(sumBuilder,myCalculatorSum);

I play three possible option:

  • The MethodAttributes
  • The CallingConventions
  • And the DefineMethodOverride method

My concept: Make the method Public obviously and HideBySig. Additional ReuseSlot in the vtable and called it with ExplicitThis.
Any idea how to achieve this? Or need some more nasty thing?
I know there is frameworks outside, but I want to understand the concept of this.

svick
  • 236,525
  • 50
  • 385
  • 514
Péter
  • 2,161
  • 3
  • 21
  • 30
  • 2
    You can't override non-virtuals. AFAIK, Castle can't do it either. Something like PostSharp can, but that works by actually changing the compiled assembly, not creating a new derived type. – svick Jun 09 '14 at 12:28
  • possible duplicate [link](http://stackoverflow.com/questions/1853896/is-it-possible-to-override-a-non-virtual-method) – Sargis Koshkaryan Jun 09 '14 at 12:41
  • @svick: You are right. The inheritance proxy only supported for virtual members in castle. But my basic idea is that the IL is know more than the C#. (For example main method without class :) ) – Péter Jun 10 '14 at 06:40
  • @SargisKoshkaryan: The linked post is about C# not IL – Péter Jun 10 '14 at 06:41

1 Answers1

3

If you specifically want to override the method, then as svick said in a comment, your out of luck. The reason is that if the method is not marked as virtual in IL (which is a little different to virtual in C#) then it will not be given a slot in the virtual method table, and so no way for the subclass to override it. Sometimes C# will compile a non-virtual method as virtual and final in IL but if you try to override a final method then it will fail verification as a security risk.

If you are trying to replace the behavior of the method (such as when mocking the object) then there are still potentially some options.

Remoting

If the object happens to inherit from MarshalByRefObject then you can use the remoting system to mock the object. Essentially, telling the CLR that the object exists elsewhere and that you will be marshaling the messages its behalf. This approach will allow you to mock non-virtual instance methods, so long as they are defined on an object inheriting from MarshalByRefObject and are called from outside the object.

Profiling

The profiling API allows for instrumentation at jit time. This allows you to change the behavior of any managed method, including static methods in the framework. The flexibility here comes at a cost though, it takes considerably more effort to implement and requires that the process is run with a particular profiler in place - a significant problem if you ever actually need to profile your code.

I have seen both of these approaches used in one mock library or another and I would consider both inappropriate for production code.

Brian Reichle
  • 2,798
  • 2
  • 30
  • 34