我需要在winform .NET应用程序中测量每个方法的执行持续时间。输出存入文件。
我不想将代码的开始时间和结束时间放在每个.NET方法中,我想知道是否有一个库可以通过更改配置文件来打开/关闭它。
感谢。
Koronx
答案 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<>));
使用此配置,我们可以container
为IUseCaseHandler<MoveCustomerUseCase>
请求,MoveCustomerUseCaseHandler
将DurationMeasuringUseCaseHandlerDecorator<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()]
这方面的积极方面是它完全无创,并且不需要对现有代码进行任何更改。