我开始使用属性,对于此示例,代码是使用PostSharp 2.0编写的。
我想要做的是具有Stopwatch
属性或调用方法可以访问经过时间的方法。
我目前正在使用C#4.0编写此代码
示例属性代码:
[Serializable]
public class StopwatchAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
// Create new stopwatch
Stopwatch stopwatch = new Stopwatch();
// Begin timing
stopwatch.Start();
args.MethodExecutionTag = stopwatch;
}
public override void OnExit(MethodExecutionArgs args)
{
Stopwatch stopwatch = (Stopwatch)args.MethodExecutionTag;
// Stop timing
stopwatch.Stop();
// Write result
Debug.WriteLine("Time elapsed: {0} ms", stopwatch.Elapsed);
}
}
使用属性
[Stopwatch]
public string Search(string LineNo)
{
// Search for something
// Is it possible to know how long (from Stopwatch attribute) Search took
}
public void CallSearch
{
string x = Search("xyz");
// Is it possible to know how long (from Stopwatch attribute) Search took
}
我得到了经过时间的输出。
但是,无论如何都要扩展这个以便我可以发送经过的时间。
理想情况下,我希望看到Search
从CallSearch
获取了多长时间,但如果我甚至可以在Search
中获得结果然后以某种方式返回它,那就没问题。< / p>
作为一种解决方法,我目前正在使用"Hole in the Middle"模式。
谢谢
答案 0 :(得分:1)
我认为属性是只读的,并且在编译时完全确定。编译代码后,您无法影响属性。也许你可以保留一个静态的Dictionary(将delegates或MemberInfo映射到执行时间值)来跟踪标记为跟踪其执行时间的每个方法的最后执行时间?
答案 1 :(得分:1)
嗯,在方法结束后,属性中的变量将不复存在。为此,您需要评估数据的日志或其他持久性源。您可以将数据写入静态List或类似的东西,但是没有可以编写的代码,它们将反射性地检查属性本身,以确定具有该属性的方法的最后一次运行所花费的时间(除非属性类具有检查相同的持久存储。)
正如您所写的那样,该属性只是CLR以特殊方式使用的类;它检查是否存在面向方面的属性,根据需要实例化任何属性,并根据需要调用任何处理程序。该类只在运行时需要它的范围内,一旦它不是,它就是GCed。要使用面向方面目的范围之外的属性,可以使用其类型,和/或使用Activator创建它的新实例。
一件事;属性可以具有静态属性。因此,您可以定义静态秒表实例,并将其设置为最近在OnExit中停止的秒表。这将允许您静态地确定用属性修饰的最后一个执行方法的时间。
答案 2 :(得分:0)
可能的解决方案(对不起,我没有测试它,但想法必须明确):
[Serializable]
public class StopwatchAttribute : OnMethodBoundaryAspect
{
[ThreadStatic]
private static Stopwatch stopwatch = null;
public override void OnEntry(MethodExecutionArgs args)
{
var sw = stopwatch ?? new Stopwatch();
args.MethodExecutionTag = sw; // Better to move this line before .Start
sw.Start();
}
public override void OnExit(MethodExecutionArgs args)
{
var sw = (Stopwatch) args.MethodExecutionTag;
sw.Stop();
Debug.WriteLine("Time elapsed: {0} ms", sw.Elapsed);
}
public static Stopwatch Measure(Action action)
{
var oldStopwatch = stopwatch;
stopwatch = new Stopwatch();
try {
// !!! Btw, you can measure everything right here.
action.Invoke();
return stopwatch;
}
finally {
stopwatch = oldStopwatch;
}
}
}
隐含用法:
[Stopwatch]
public string Search(string LineNo)
{
// Search for something
// Is it possible to know how long (from Stopwatch attribute) Search took
}
public void CallSearch
{
var stopwatch = StopwatchAttribute.Measure(() => {
string x = Search("xyz");
});
Console.WriteLine("Time elapsed: {0} ms", stopwatch.Elapsed);
}
如您所见,PostSharp的使用似乎不太必要。它可用于记录此类计时,但您必须使用类似方法或您自己的日志访问API来获取记录时间。
答案 3 :(得分:0)