使用属性(.net核心)衡量方法执行时间

时间:2018-09-19 09:24:28

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

我有兴趣衡量执行特定方法所花费的时间。

我当时想使用“自定义属性”来实现此目的非常方便,而不是使用乱码方法来启动/停止秒表并发送至记录器。如果我可以使用属性来修饰所讨论的方法,那将真的很方便!

根据本文,我能够创建一个自定义属性: 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核心应用中采用这种方法吗?预先感谢您的任何指点!

3 个答案:

答案 0 :(得分:1)

.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/

答案 1 :(得分: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 :(得分:0)

@ 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