.NET Core:在方法之前和之后执行的属性

lss*_*lss 5 c# .net-core

在Java中,可以使用AspectJ在执行方法之前和之后使用方法注释添加行为。由于C#属性似乎非常相似,所以我想知道是否有可能实现类似的行为。我一直在寻找的几个教程和其他来源(123),但没有人帮助我。

我认为也许可以通过将代码插入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 如何运作,但我的属性甚至没有实例化?以及如何使属性在修饰方法之前和之后运行?

And*_*ren 6

就像使用 Java 和 AspectJ 一样,您需要单独的 AoP 工具来在 .NET 中注入这样的代码。

PostSharp就是这样一种工具,可能是最著名的工具。我相信他们从第 5 版开始就支持 .NET 核心。


Him*_*ere 5

您需要一些能够适当处理属性的框架。仅因为属性存在并不意味着它将产生任何影响。

我写了一些简单的引擎来做到这一点。它将确定传递的属性是否存在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)

  • 因为`nameof` 产生编译时常量,在C# 6 中你实际上可以使用`[MyAttribute(PreAction = nameof(Handler1), PostAction = nameof(Handler2))]`,好处很明显。 (4认同)

Car*_*nco 5

这可以使用DynamicProxy来完成。

有一种内存缓存技术的实现,其逻辑在调用方法之前执行。可以扩展到检查这样的属性是否存在

var attribute = Attribute.GetCustomAttribute(invocation.MethodInvocationTarget, typeof(CachedAttribute)) as CachedAttribute;
if (attribute != null)
{
  ...
}
Run Code Online (Sandbox Code Playgroud)

上面的代码可以放在InterceptInterceptor实现的方法内部。CachedAttribute将是你的属性。