用于测量.NET winform app中每个方法的执行持续时间的库

时间:2012-10-16 07:00:06

标签: .net winforms

我需要在winform .NET应用程序中测量每个方法的执行持续时间。输出存入文件。

我不想将代码的开始时间和结束时间放在每个.NET方法中,我想知道是否有一个库可以通过更改配置文件来打开/关闭它。

感谢。

Koronx

2 个答案:

答案 0 :(得分:0)

尝试以这样的方式设计您的应用程序,以便轻松添加这种交叉关注点。例如,将单个用例的业务逻辑/行为放在一个类中,并使用通用接口进行装饰:

public interface IUseCaseHandler<TUseCase>
{
    void Handle(TUseCase useCase);
}

用例的定义是一个简单的DTO(数据传输对象):

public class MoveCustomerUseCase
{
    public int CustomerId { get; set; }

    public Address Address { get; set; }
}

实现可能如下所示:

public class MoveCustomerUseCaseHandler
    : IUseCaseHandler<MoveCustomerUseCase>
{
    public void Handle(MoveCustomerUseCase useCase)
    {
        // todo: business logic
    }
}

你在这里获得了什么?好吧,当所有用例处理程序都实现IUseCaseHandler<T>接口时,您可以为所有处理程序编写一个decorator

public class DurationMeasuringUseCaseHandlerDecorator<TUseCase>
    : IUseCaseHandler<TUseCase>
{
    private readonly IUseCaseHandler<TUseCase> decoratedInstance;
    private readonly ILogger logger;

    public DurationMeasuringUseCaseHandlerDecorator(
        IUseCaseHandler<TUseCase> decoratedInstance, 
        ILogger logger)
    {
        this.decoratedInstance = decoratedInstance;
        this.logger = logger;
    }

    public void Handle(TUseCase useCase)
    {
        var stopwatch = System.Diagnostics.Stopwatch.StartNew();

        try
        {
            // call the real use case handler
            this.decoratedInstance.Handle(useCase);
        }
        finally
        {
            this.logger.Log(typeof(TUseCase).Name + 
                " executed in " + 
                stopwatch.ElapsedMiliseconds + " ms.");
        } 
    }
}

这似乎是一些日志记录的代码不是吗?实际上并非如此。这是您必须编写该代码的唯一时间,并且您不必更改任何用例处理程序来添加测量。您可以像这样包装所有处理程序:

// Composing the object graph
IUseCaseHandler<MoveCustomerUseCase> handler = 
    newMoveCustomerUseCaseHandler(
        new MoveCustomerUseCaseHandler(),
        new Logger());

// Using the object (somewhere else in the code)
handler.Handle(new MoveCustomerUseCase { CustomerId = id, Address = adr });

但是现在我们每次想要使用它时仍然必须将对象图连接在一起?这就是IoC容器的用武之地。例如,使用Simple Injector,需要一行代码来注册系统中的所有用例处理程序:

container.RegisterManyForOpenGeneric(typeof(IUseCaseHandler<>),
    typeof(IUseCaseHandler<>).Assembly);

RegisterManyForOpenGeneric方法遍历程序集中的所有公共类型,并通过其封闭的通用表示(例如IUseCaseHandler<T>)注册实现IUseCaseHandler<MoveCustomerUseCase>接口的所有具体类型。

用装饰器包装所有处理程序只是另一个单行程序:

container.RegisterDecorator(typeof(IUseCaseHandler<>),
    typeof(DurationMeasuringUseCaseHandlerDecorator<>));

使用此配置,我们可以containerIUseCaseHandler<MoveCustomerUseCase>请求,MoveCustomerUseCaseHandlerDurationMeasuringUseCaseHandlerDecorator<MoveCustomerUseCase>包裹var handler = container.GetInstance<IUseCaseHandler<MoveCustomerUseCase>>(); handler.Handle(new MoveCustomerUseCase { CustomerId = id, Address = adr });

{{1}}

答案 1 :(得分:0)

您可以将AOP库用于C#,如postsharp

来自postharp文档的修改示例:

/// <summary>
/// Aspect that, when applied on a method, emits a trace message before and
/// after the method execution.
/// </summary>
[Serializable]
public class TraceAttribute : OnMethodBoundaryAspect
{
    private string methodName;
    private DateTime startTime;

    /// <summary>
    /// Method executed at build time. Initializes the aspect instance. After the execution
    /// of <see cref="CompileTimeInitialize"/>, the aspect is serialized as a managed 
    /// resource inside the transformed assembly, and deserialized at runtime.
    /// </summary>
    /// <param name="method">Method to which the current aspect instance 
    /// has been applied.</param>
    /// <param name="aspectInfo">Unused.</param>
    public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo)
    {
        this.methodName = method.DeclaringType.FullName + "." + method.Name;
    }

    /// <summary>
    /// Method invoked before the execution of the method to which the current
    /// aspect is applied.
    /// </summary>
    /// <param name="args">Unused.</param>
    public override void OnEntry(MethodExecutionArgs args)
    {
        startTime = DateTime.Now;
        Trace.TraceInformation("{0}: Enter", this.methodName);
        Trace.Indent();
    }

    /// <summary>
    /// Method invoked after successfull execution of the method to which the current
    /// aspect is applied.
    /// </summary>
    /// <param name="args">Unused.</param>
    public override void OnSuccess(MethodExecutionArgs args)
    {
        Trace.Unindent();
        var duration = DateTime.Now - startTime;
        Trace.TraceInformation("{0}: Success, Duration: {1}ms", this.methodName, duration.TotalMilliseconds);
    }
}

要将其应用于项目中的每个方法,只需编辑assemblyinfo.cs并添加:

 [assembly: SomeNamespace.TraceAttribute()]

这方面的积极方面是它完全无创,并且不需要对现有代码进行任何更改。