关于c#:如何在运行时替换方法实现?

How do I replace a method implementation at runtime?

我想拥有属性getter和方法,我可以用自己的自定义属性进行装饰,并根据该属性的存在,用不同的实现替换方法体。 此外,不同的实现将需要知道给它装饰方法的自定义属性的构造函数参数。

这显然可以通过AOP来完成,比如PostSharp或LinFu,但是我想知道是否有一种方法可以做到这一点,不涉及构建后的处理步骤,因为添加使项目更加复杂,这比我想要的更多。


使用传统的.Net API无法实现这一目标。方法体在编译时是固定的,不能更改。

我说传统,但因为使用分析器和ENC API,技术上可以更改方法体。但是这些API在受限制的情况下运行,并且不被视为通用API。


任何好的AOP框架都可以在运行时工作。
我目前正在研究其中一个具备这种能力的人。

您可以在此处找到它:NConcer .NET运行时面向方面编程

一个小例子向您展示它是如何工作的......

假定的自定义属性:

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

标记classe的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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);
    }
}

使用案例:

1
2
3
4
static public void main(string[] args)
{
    Aspect.Weave<MyAspect>(method => method.IsDefined(typeof(MyAttribute1), true));
}


存在一些允许您在运行时动态更改任何方法的框架:

  • Prig:自由开源!
  • Harmony Open Source和MIT获得许可,但.net支持目前似乎不完整。
  • Microsoft Fakes:Commercial,包含在Visual Studio Premium和Ultimate中,但不包括社区和专业版
  • Telerik JustMock:商业,"精简"版本可用
  • Typemock隔离器:商业

根据您的具体需求,有一些可能性。从.NET 1.0开始,就可以使用System.Runtime.Remoting.Proxies命名空间中的类型拦截调用。