2

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

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

谢谢。

科龙克斯

4

2 回答 2

0

您可以使用 C# 的 AOP 库,如postsharp

postsharp 文档中的修改示例:

/// <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()]

这样做的积极方面是它完全是非侵入性的,并且不需要更改您现有的代码。

于 2012-10-16T07:44:03.473 回答
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>编写一个装饰器:

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<>));

使用此配置,我们可以请求containerfor an IUseCaseHandler<MoveCustomerUseCase>,它会以MoveCustomerUseCaseHandler用 a 包裹的形式返回DurationMeasuringUseCaseHandlerDecorator<MoveCustomerUseCase>

var handler =
    container.GetInstance<IUseCaseHandler<MoveCustomerUseCase>>();

handler.Handle(new MoveCustomerUseCase 
{
    CustomerId = id, Address = adr
});
于 2012-10-16T07:41:17.760 回答