You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为C#项目所有函数批量添加Stopwatch计时功能

批量给C#函数添加计时的几种实用方法

1. 使用AOP框架(PostSharp)

这是最省心的方案,通过特性就能批量给类或方法注入计时逻辑,无需手动修改每个函数。

首先安装PostSharp NuGet包,然后定义一个计时特性:

[Serializable]
public class TimingAttribute : OnMethodBoundaryAspect
{
    private Stopwatch _stopwatch;

    public override void OnEntry(MethodExecutionArgs args)
    {
        _stopwatch = Stopwatch.StartNew();
    }

    public override void OnExit(MethodExecutionArgs args)
    {
        _stopwatch.Stop();
        Console.WriteLine($"方法 {args.Method.Name} 执行耗时: {_stopwatch.ElapsedMilliseconds}ms");
    }
}

然后直接给整个类或者单个方法加特性,编译后PostSharp会自动把计时逻辑织入:

// 给整个类的所有方法加计时
[Timing]
public class BusinessService
{
    public void ProcessOrder()
    {
        // 业务逻辑
    }

    public string GetUserInfo(int userId)
    {
        // 业务逻辑
        return "user info";
    }
}

2. 装饰器模式(适合接口驱动的项目)

如果你的项目是基于接口设计的,可以用装饰器包装每个实现类,统一添加计时逻辑,不用修改原业务代码。

比如先定义接口:

public interface IOrderService
{
    void ProcessOrder(int orderId);
}

public class OrderService : IOrderService
{
    public void ProcessOrder(int orderId)
    {
        // 原始业务逻辑
        Thread.Sleep(100);
    }
}

然后写装饰器类:

public class TimingOrderServiceDecorator : IOrderService
{
    private readonly IOrderService _innerService;

    public TimingOrderServiceDecorator(IOrderService innerService)
    {
        _innerService = innerService;
    }

    public void ProcessOrder(int orderId)
    {
        var stopwatch = Stopwatch.StartNew();
        _innerService.ProcessOrder(orderId);
        stopwatch.Stop();
        Console.WriteLine($"ProcessOrder({orderId}) 耗时: {stopwatch.ElapsedMilliseconds}ms");
    }
}

使用的时候用装饰器包装原实例:

var orderService = new TimingOrderServiceDecorator(new OrderService());
orderService.ProcessOrder(123);

如果接口很多,可以结合依赖注入容器(比如Autofac、Microsoft DI)批量注册装饰器,不用手动每个都包装。

3. 用Roslyn批量修改代码

如果需要直接给源代码添加计时逻辑,可以用Roslyn(.NET编译器平台)写个小工具,遍历项目中的所有方法,自动插入Stopwatch代码。

示例代码(简化版):

var workspace = MSBuildWorkspace.Create();
var project = await workspace.OpenProjectAsync(@"YourProject.csproj");

foreach (var document in project.Documents)
{
    var syntaxTree = await document.GetSyntaxTreeAsync();
    var root = await syntaxTree.GetRootAsync();

    // 遍历所有方法声明
    var methods = root.DescendantNodes().OfType<MethodDeclarationSyntax>();
    var newRoot = root.ReplaceNodes(methods, (original, _) =>
    {
        // 创建Stopwatch的变量声明和计时代码
        var stopwatchVar = SyntaxFactory.LocalDeclarationStatement(
            SyntaxFactory.VariableDeclaration(SyntaxFactory.ParseTypeName("var"))
                .AddVariables(SyntaxFactory.VariableDeclarator("stopwatch")
                    .WithInitializer(SyntaxFactory.EqualsValueClause(
                        SyntaxFactory.ParseExpression("Stopwatch.StartNew()")))));

        var stopCode = SyntaxFactory.ExpressionStatement(
            SyntaxFactory.ParseExpression("stopwatch.Stop()"));

        var logCode = SyntaxFactory.ExpressionStatement(
            SyntaxFactory.ParseExpression($"Console.WriteLine(\"方法 {original.Identifier.Text} 耗时: \" + stopwatch.ElapsedMilliseconds + \"ms\")"));

        // 把计时代码插入方法体开头和结尾
        var newBody = original.Body
            .WithStatements(SyntaxFactory.List(
                new[] { stopwatchVar }.Concat(original.Body.Statements).Concat(new[] { stopCode, logCode })));

        return original.WithBody(newBody);
    });

    // 保存修改后的文档
    await document.WithSyntaxRoot(newRoot).SaveAsync();
}

这个工具可以一次性给项目里的所有方法加上计时代码,注意先备份代码再运行。

4. 利用.NET的Activity/DiagnosticSource

这种方式不需要修改业务代码,通过监听诊断事件来收集方法执行时间,适合非侵入式的计时。

首先在方法中使用Activity:

public void ProcessData()
{
    using var activity = new Activity("ProcessData").Start();
    // 业务逻辑
}

然后订阅DiagnosticListener的事件来获取计时信息:

DiagnosticListener.AllListeners.Subscribe(listener =>
{
    if (listener.Name == "YourCustomListener")
    {
        listener.SubscribeWithAdapter(new ActivityListener());
    }
});

public class ActivityListener
{
    [DiagnosticName("Activity.Start")]
    public void OnActivityStart(Activity activity)
    {
        // 可记录开始时间戳
    }

    [DiagnosticName("Activity.Stop")]
    public void OnActivityStop(Activity activity)
    {
        Console.WriteLine($"Activity {activity.DisplayName} 耗时: {activity.Duration.TotalMilliseconds}ms");
    }
}

内容的提问来源于stack exchange,提问作者Gökhan AKSOY

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 23:40:35