使用属性 (.net core) 测量方法执行时间

Measure method execution time using an attribute (.net core)

我对测量执行特定方法所需的时间很感兴趣。

我认为使用自定义属性而不是使用代码向 start/stop 秒表发送代码并发送到记录器会非常方便。如果我能用一个属性来装饰这个方法,那就太方便了!

我能够按照这篇文章创建自定义属性: https://docs.microsoft.com/en-us/dotnet/standard/attributes/writing-custom-attributes

像这样:

public class MonitorExecutionTime : Attribute
{
    private Stopwatch measureExecution;

    // Start measuring on instantiation
    public MonitorExecutionTime()
    {
        measureExecution = new Stopwatch();
        measureExecution.Start();
    }

    // how do I hook into end invoke?
    public MethodHasEnded()
    {

        measureExecution.Stop();
        TimeSpan timeSpan = measureExecution.Elapsed;

        Console.WriteLine("Time: {0}h {1}m {2}s {3}ms", timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds, timeSpan.Milliseconds);
    }
}

但我不确定如何 "capture" 正在调用和结束调用执行点以启动秒表和停止秒表(以测量时间并记录它)。

有人在 .net 核心应用程序中采用过这种方法吗?在此先感谢您的指点!

.NET 中的属性不是包装器,因此您不能以那种方式使用它们。 您必须使用方法调用包装器,例如:

public class Service : IService
{
    public void Exec() {
        Wrap("Method Exec", () => {
            // do something usefull
        });
    }

    private void Wrap(string message, Action action)
    {
        var watch = Stopwatch.StartNew();
        try
        {
            action();
        }
        finally
        {
            watch.Stop();
            Console.WriteLine($"{message} executed in {watch.ElapsedMilliseconds} ms");
        }
    }
}

如果你想包装class或者接口的所有方法,你应该看看面向切面编程,例如这篇文章:https://www.c-sharpcorner.com/article/aspect-oriented-programming-in-c-sharp-using-dispatchproxy/

运行时不调用属性。但是您可以使用 Fody 之类的库进行程序集编织 - 在您的程序集编译成标有您的自定义属性的方法后自动添加代码。

其实已经有你想要实现的实现了- Method Timer

这是它的工作原理(copy/paste 来自文档)。您的代码:

public class MyClass
{
    [Time]
    public void MyMethod()
    {
        //Some code u are curious how long it takes
        Console.WriteLine("Hello");
    }
}

实际编译成最终汇编的是什么

public class MyClass
{
    public void MyMethod()
    {
        var stopwatch = Stopwatch.StartNew();
        try
        {
            //Some code u are curious how long it takes
            Console.WriteLine("Hello");
        }
        finally
        {
            stopwatch.Stop();
            Trace.WriteLine("MyClass.MyMethod " + stopwatch.ElapsedMilliseconds + "ms");
        }
    }
}

您可以编写自定义拦截器代码以避免使用 Trace.WriteLine 并按照您想要的方式进行记录。

@Igore-goyda - 你的 post 让我找到了我需要的东西。总结一下其他人 - 有两种方法可以拦截方法和 运行 一些自定义处理。通过代理或使用 IL 重写器。

我发现这篇文章很好地解释了:http://jeffbelback.me/posts/2015/06/01/principles-of-aop/

我认为 Proxy 方法最适合我(不喜欢我的代码在编译后被修改的概念),并且能够按照本文使用 Autofac 实施合适的解决方案: https://nearsoft.com/blog/aspect-oriented-programming-aop-in-net-core-and-c-using-autofac-and-dynamicproxy/

Autofac 文档也帮助了我: https://autofaccn.readthedocs.io/en/latest/advanced/interceptors.html?highlight=proxy