在Java中,可以使用AspectJ在执行方法之前和之后使用方法注释添加行为。由于C#属性似乎非常相似,所以我想知道是否有可能实现类似的行为。我一直在寻找的几个教程和其他来源(1,2,3),但没有人帮助我。
我认为也许可以通过将代码插入Attribute构造函数并使其成为可处理的方式来模仿行为,如下所示:
[AttributeUsage(AttributeTargets.Method)]
public class MyWritingAttribute : Attribute, IDisposable
{
public MyWritingAttribute()
{
Console.WriteLine("Attribute created");
}
public void Dispose()
{
Console.WriteLine("Attribute disposed");
}
}
Run Code Online (Sandbox Code Playgroud)
但是,当使用这样的属性时,只有Hello world!在控制台中显示:
class Program
{
static void Main(string[] args)
{
SayHelloWorld();
Console.ReadLine();
}
[MyWriting]
private static void SayHelloWorld()
{
Console.WriteLine("Hello World!");
}
}
Run Code Online (Sandbox Code Playgroud)
我当时在想控制台可能无法在该属性中访问,但是即使将其替换为throw new Exception()表达式,也不会引发异常。StringLengthAttributeEF 如何运作,但我的属性甚至没有实例化?以及如何使属性在修饰方法之前和之后运行?
您需要一些能够适当处理属性的框架。仅因为属性存在并不意味着它将产生任何影响。
我写了一些简单的引擎来做到这一点。它将确定传递的属性是否存在action,如果存在,则获取反射的方法以执行它们。
class Engine
{
public void Execute(Action action)
{
var attr = action.Method.GetCustomAttributes(typeof(MyAttribute), true).First() as MyAttribute;
var method1 = action.Target.GetType().GetMethod(attr.PreAction);
var method2 = action.Target.GetType().GetMethod(attr.PostAction);
// now first invoke the pre-action method
method1.Invoke(null, null);
// the actual action
action();
// the post-action
method2.Invoke(null, null);
}
}
public class MyAttribute : Attribute
{
public string PreAction;
public string PostAction;
}
Run Code Online (Sandbox Code Playgroud)
当然,您需要一些null技巧,例如,在方法不存在或不是静态的情况下。
现在,您必须使用属性装饰操作:
class MyClass
{
[MyAttribute(PreAction = "Handler1", PostAction = "Handler2")]
public void DoSomething()
{
}
public static void Handler1()
{
Console.WriteLine("Pre");
}
public static void Handler2()
{
Console.WriteLine("Post");
}
}
Run Code Online (Sandbox Code Playgroud)
最后,您可以在我们的引擎中执行该方法:
var engine = new Engine();
var m = new MayClass();
engine.Execute(m.DoSomething);
Run Code Online (Sandbox Code Playgroud)
有一种内存缓存技术的实现,其逻辑在调用方法之前执行。可以扩展到检查这样的属性是否存在
var attribute = Attribute.GetCustomAttribute(invocation.MethodInvocationTarget, typeof(CachedAttribute)) as CachedAttribute;
if (attribute != null)
{
...
}
Run Code Online (Sandbox Code Playgroud)
上面的代码可以放在InterceptInterceptor实现的方法内部。CachedAttribute将是你的属性。