我想拥有可以用我自己的自定义属性装饰的属性获取器和方法,并根据该属性的存在用不同的实现替换方法主体。此外,不同的实现将需要知道赋予自定义属性的构造函数参数,该属性在其中装饰方法。
这显然可以使用 AOP 来完成,比如 PostSharp 或 LinFu,但我想知道是否有一种方法可以做到这一点,它不涉及构建后处理步骤,因为添加它会使项目变得比我更喜欢的复杂化。
我想拥有可以用我自己的自定义属性装饰的属性获取器和方法,并根据该属性的存在用不同的实现替换方法主体。此外,不同的实现将需要知道赋予自定义属性的构造函数参数,该属性在其中装饰方法。
这显然可以使用 AOP 来完成,比如 PostSharp 或 LinFu,但我想知道是否有一种方法可以做到这一点,它不涉及构建后处理步骤,因为添加它会使项目变得比我更喜欢的复杂化。
有几个框架允许您在运行时动态更改任何方法:
使用传统的 .Net API 无法实现这一点。方法体在编译时是固定的,不能更改。
我说的是传统的,因为使用分析器和 ENC API 在技术上可以更改方法体。但这些 API 在受限环境下运行,不被视为通用 API。
任何好的 AOP 框架都可以在运行时工作。我目前正在以这种能力研究其中一个。
你可以在这里找到它:NConcern .NET runtime Aspect-Oriented Programming
一个小例子来告诉你它是如何工作的......
假定的自定义属性:
[AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited=true)]
public class MyAttribute1 : Attribute
{
public string MyAttributeValue;
}
标记类的示例:
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);
}
}
用例:
static public void main(string[] args)
{
Aspect.Weave<MyAspect>(method => method.IsDefined(typeof(MyAttribute1), true));
}
有一些可能性,具体取决于您的确切需求。从 .NET 1.0 开始,就可以使用System.Runtime.Remoting.Proxies 命名空间中的类型拦截调用。