【问题标题】:Measure method execution time using an attribute (.net core)使用属性(.net 核心)测量方法执行时间
【发布时间】:2018-09-19 09:24:28
【问题描述】:

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

我认为使用自定义属性而不是乱扔代码来启动/停止秒表并发送到记录器会非常方便。如果我可以使用属性来装饰有问题的方法,那将非常方便!

我能够在这篇文章之后创建自定义属性: 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);
    }
}

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

有没有人在 .net 核心应用程序中采用这种方法?提前感谢您的任何指点!

【问题讨论】:

  • 我不确定,但你检查过你的属性类的析构函数是什么时候执行的吗?可以将其用作您的方法结束挂钩吗?

标签: logging .net-core azure-application-insights custom-attributes stopwatch


【解决方案1】:

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

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

这是它的工作原理(从文档中复制/粘贴)。你的代码:

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 并按照您想要的方式进行日志记录。

【讨论】:

    【解决方案2】:

    .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");
            }
        }
    }
    

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

    【讨论】:

      【解决方案3】:

      @Igore-goyda - 你的帖子让我找到了我需要的东西。对其他人进行总结 - 有两种方法可以拦截方法并运行一些自定义处理。通过代理或使用 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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-09-20
        • 2012-05-14
        • 1970-01-01
        • 1970-01-01
        • 2014-06-26
        • 1970-01-01
        • 2020-05-08
        • 2019-05-30
        相关资源
        最近更新 更多