V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
irisdev
V2EX  ›  C#

请教下 C#有没有办法用装饰器全局监控方法执行时间

  •  
  •   irisdev · 17 天前 · 548 次点击
    现在手上有个老的 mvc 项目,有些方法执行时间比较长,每次都是代码第一行 StopWatch 监控一下执行时间写入表里面监控下。不知道有没有办法像 python 的类装饰器函数一样在类或方法之前写个注解就可以监控执行时间的方案,.net 的 Attribute 似乎做不到这种运行时的监控。想了下可能有两个方案:

    1.写个方法传个委托,然后在委托执行前后执行一下 StopWatch ,把业务代码都传到这个委托里。但是这么做很不方便,貌似意义不大

    2..net 有个开源库 MethodTime.Fody ,加上一个[Time]特性就可以实现我想要的效果,但是内网环境,而且我不是 Leader ,不敢随便引入其他包

    请教下各位大佬在.net framework 里面有没有遇到过类似的需求,有没有什么比较好的实现方案,谢谢回复
    7 条回复    2024-12-13 17:41:56 +08:00
    quan01994
        1
    quan01994  
       17 天前   ❤️ 1
    可以使用
    APM 。
    IOC + AOP 。
    静态织入。
    irisdev
        2
    irisdev  
    OP
       17 天前 via Android
    @quan01994 谢谢佬,我没太懂,我去了解一下
    yuhuai
        3
    yuhuai  
       17 天前   ❤️ 1
    说实话,如果是测试该用 benchmark.net ,但你现在属于是被你自己给误导了,你是想监控哪些函数执行时间长,这时候应该用 dotTrace 这种工具在压力下进行监测,可以直接按耗时进行排序,再针对性处理
    yuhuai
        4
    yuhuai  
       17 天前   ❤️ 1
    附加一下,上面的名称被识别为网址了,实际测试框架地址是这个 https://github.com/dotnet/BenchmarkDotNet
    cxe2v
        5
    cxe2v  
       17 天前   ❤️ 1
    我一问 gpt ,代码就出来了,不比在这里问这些网友快?


    }

    protected override object Invoke(MethodInfo targetMethod, object[] args)
    {
    // 检查方法是否有 MeasureTimeAttribute
    if (targetMethod.GetCustomAttribute<MeasureTimeAttribute>() != null)
    {
    var stopwatch = Stopwatch.StartNew();
    try
    {
    // 执行实际方法
    return targetMethod.Invoke(_decorated, args);
    }
    finally
    {
    stopwatch.Stop();
    Console.WriteLine($"方法 {targetMethod.Name} 执行耗时: {stopwatch.ElapsedMilliseconds} ms");
    }
    }
    else
    {
    // 没有特性直接调用方法
    return targetMethod.Invoke(_decorated, args);
    }
    }
    }
    3. 应用到目标类
    csharp
    复制代码
    public interface IExampleService
    {
    [MeasureTime]
    void DoSomething();

    void DoOtherThing();
    }

    public class ExampleService : IExampleService
    {
    public void DoSomething()
    {
    // 模拟耗时操作
    System.Threading.Thread.Sleep(100);
    Console.WriteLine("执行 DoSomething");
    }

    public void DoOtherThing()
    {
    Console.WriteLine("执行 DoOtherThing");
    }
    }
    4. 使用动态代理包装实例
    csharp
    复制代码
    class Program
    {
    static void Main()
    {
    var service = MethodInterceptor<IExampleService>.Create(new ExampleService());

    service.DoSomething(); // 记录耗时
    service.DoOtherThing(); // 不记录耗时
    }
    }
    cxe2v
        6
    cxe2v  
       17 天前   ❤️ 1
    @cxe2v

    1. 定义一个自定义特性
    创建一个特性类,用于标记需要记录耗时的方法:

    csharp
    复制代码
    [AttributeUsage(AttributeTargets.Method, Inherited = true)]
    public class MeasureTimeAttribute : Attribute
    {
    }
    2. 使用动态代理拦截方法调用
    通过 AOP (面向切面编程)的方式,例如使用 Castle DynamicProxy 或 DispatchProxy ,拦截方法的执行并记录耗时。

    使用 DispatchProxy 示例:
    csharp
    复制代码
    using System;
    using System.Diagnostics;
    using System.Reflection;

    public class MethodInterceptor<T> : DispatchProxy
    {
    private T _decorated;

    public static T Create(T decorated)
    {
    object proxy = Create<T, MethodInterceptor<T>>();
    ((MethodInterceptor<T>)proxy)._decorated = decorated;
    return (T)proxy;
    irisdev
        7
    irisdev  
    OP
       17 天前
    @cxe2v gpt 的这段代码...给每个 controller 都包一层还不如直接写在每个方法里面。快不等于好
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1730 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 20ms · UTC 16:28 · PVG 00:28 · LAX 08:28 · JFK 11:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.