如何在运行时替换方法实现?
我想拥有属性getter和方法,我可以用自己的自定义属性进行装饰,并根据该属性的存在,用不同的实现替换方法体。 此外,不同的实现需要知道赋予自定义属性的构造函数参数,在该属性中它装饰方法。
这显然可以通过AOP完成,比如PostSharp或LinFu,但是我想知道是否有一种方法可以做到这一点,不涉及构建后的处理步骤,因为添加使项目更加复杂化。
使用传统的.Net API无法实现这一目标。 方法体在编译时是固定的,不能更改。
我说传统,但因为使用分析器和ENC API,技术上可以更改方法体。 但是这些API在受限制的情况下运行,并且不被视为通用API。
任何好的AOP框架都可以在运行时工作。 我目前正在研究其中一个具有这种能力的人。
您可以在此处找到它: NConcer .NET运行时面向方面编程
一个小例子向您展示它是如何工作的……
假定的自定义属性:
[AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited=true)] public class MyAttribute1 : Attribute { public string MyAttributeValue; }
标记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 Advise(MethodInfo method) { var myattribute1 = method.GetCustomAttributes(typeof(MyAttribute1), true).Cast().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); } }
使用案例:
static public void main(string[] args) { Aspect.Weave(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命名空间中的类型拦截调用。