How do I replace a method implementation at runtime?
Asked Answered
O

4

5

I'd like to have property getters and methods that I can decorate with my own custom attribute and based on the presence of that attribute replace the method bodies with a different implementation. Also, that different implementation will need to know the constructor arguments given to the custom attribute where it decorates the method.

This can obviously be done with AOP, like PostSharp or LinFu, but I'm wondering if there's a way to do this that does not involve a post-build processing step because adding that complicates the project more than I would prefer.

Overtly answered 17/6, 2010 at 14:58 Comment(6)
Which version of the .NET framework do you use? In .NET 4 you can write dynamic classes pretty liberally with the dynamic keyword. Theres also the ExpandoObject, which is worth checking out.Hark
I would really like to come up with an implementation that is not restricted to v4 of the framework. The particular project I'm hoping to use this in first is built against .Net v3.5.Overtly
Possible duplicate of Dynamically replace the contents of a C# method?Millda
@Millda more like that question is a duplicate of this one, which I asked a year earlier.Overtly
this is old, but i must be missing something, why Replace the method, and not just call a different method. if(something) callThis(); else callThat();... is the branch that expensive in your situation? or is it memory footprint you are after?Impetigo
@TomerW The goal was to automatically generate the implementation based off declarative attributes to reduce hand-written boilerplate code.Overtly
F
2

Using the traditional .Net APIs there is no way to achieve this. Method bodies are fixed at compile time and cannot be changed.

I say traditional though because with the profiler and ENC APIs it's technically possible to change method bodies. But these APIs operate in constrained circumstances and are not considered to be general purpose APIs.

Forsterite answered 17/6, 2010 at 15:4 Comment(5)
But it most definitely can be done. .Net AOP frameworks perform modifications like this. NHibernate dynamically proxies whole classes. Just because there's not a System.Reflection.Method.ReplaceWith(...) doesn't mean I can't do this without excessive complexity, I'm sure.Overtly
@qstarin while I'm not familiar with all of them I know that some of these frameworks achieve this by modifying the IL directly and not while the process is executing. There is no traditional .Net API that provides this capability.Forsterite
hrm ... sticky problem. I don't really like any of the AOP's way of doing this.Overtly
I was loathe to accept your answer initially. But after even more research I think I have to accept that you are in fact correct. I cannot find any leads on any reasonable way to accomplish this without leveraging a post-build AOP step. Although ... ayende hints at something that piques my curiosity: ayende.com/Blog/archive/2009/11/19/can-you-hack-this-out.aspxOvertly
You could do something that is functionally equivalent by executing a delegate in your methods and swap out the delegate at runtime. This would be like implementing a vtable effectively.Mcguire
P
7

There exists a couple of frameworks that allows you to dynamically change any method at runtime:

  • Harmony Free and Open Source (MIT)!
  • Prig: Free and Open Source (MIT), requires Visual Studio extension and running programs under a launcher, not updated since 2017.
  • Microsoft Fakes: Commercial, included in Visual Studio Enterprise (Premium and Ultimate for older versions) but not Community and Professional
  • Telerik JustMock: Commercial, a "lite" version is available
  • Typemock Isolator: Commercial
Pickering answered 7/12, 2016 at 14:20 Comment(1)
Harmony 2.0 supports everything except the restricted Net Standard API that Unity now uses in one of their profiles (the other Net 4 profile has the Reflection:Emit space not stubbed out and works just fine).Officinal
F
2

Using the traditional .Net APIs there is no way to achieve this. Method bodies are fixed at compile time and cannot be changed.

I say traditional though because with the profiler and ENC APIs it's technically possible to change method bodies. But these APIs operate in constrained circumstances and are not considered to be general purpose APIs.

Forsterite answered 17/6, 2010 at 15:4 Comment(5)
But it most definitely can be done. .Net AOP frameworks perform modifications like this. NHibernate dynamically proxies whole classes. Just because there's not a System.Reflection.Method.ReplaceWith(...) doesn't mean I can't do this without excessive complexity, I'm sure.Overtly
@qstarin while I'm not familiar with all of them I know that some of these frameworks achieve this by modifying the IL directly and not while the process is executing. There is no traditional .Net API that provides this capability.Forsterite
hrm ... sticky problem. I don't really like any of the AOP's way of doing this.Overtly
I was loathe to accept your answer initially. But after even more research I think I have to accept that you are in fact correct. I cannot find any leads on any reasonable way to accomplish this without leveraging a post-build AOP step. Although ... ayende hints at something that piques my curiosity: ayende.com/Blog/archive/2009/11/19/can-you-hack-this-out.aspxOvertly
You could do something that is functionally equivalent by executing a delegate in your methods and swap out the delegate at runtime. This would be like implementing a vtable effectively.Mcguire
P
1

It is possible with any good AOP framework working at runtime. I currently work on one of them with this capacity.

You can find it here : NConcern .NET runtime Aspect-Oriented Programming

A little example to show you how it work...

The supposed custom attribute :

[AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited=true)]
public class MyAttribute1 : Attribute
{
    public string MyAttributeValue;
}

Example of a marked classe :

public class Calculator
{
    [MyAttribute1(MyAttributeValue="Hello World")]
    public int Add(int a, int b)
    {
        return a + b;
    }
}



public class MyAspect : IAspect
{
    //This code will be executed to create a decorator, not in nominal execution flow (You don't have to stress with performance here)
    public IEnumerable<IAdvice> Advise(MethodInfo method)
    {
        var myattribute1 = method.GetCustomAttributes(typeof(MyAttribute1), true).Cast<MyAttribute1>().SingleOrDefault();

        //If attribute is not defined, do not return an "advice"
        if (myattribute1 == null) { yield break; }

        //Get your attribute property.
        var myattributevalue = myattribute1.MyAttributeValue;

        //define your substitute method
        var signature= new Type[] { method.DeclaringType }.Concat(method.GetParameters().Select(parameter => parameter.Type)).ToArray();
        var dynamicMethod = new DynamicMethod(string.Empty, method.ReturnType, signature, method.DeclaringType, true);
        var body = dynamicMethod.GetILGenerator();

        //TODO : emit your code! maybe use your attribute field value to know what kind of replacement you want to do...
        body.Emit(OpCodes.Ret);

        //define the replacement
        yield return new Advice(dynamicMethod);
    }
}

Use case :

static public void main(string[] args)
{
    Aspect.Weave<MyAspect>(method => method.IsDefined(typeof(MyAttribute1), true));
}
Pavkovic answered 9/12, 2016 at 16:23 Comment(0)
S
0

There are some possibilities, depending on your exact needs. Ever since .NET 1.0, it has been possible to intercept calls using the the types in the System.Runtime.Remoting.Proxies namespace.

Stacy answered 21/11, 2013 at 15:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.