I'm trying to create some stats about method call duration in a library. Instead of wrapping each method call to the library with lines to time and track it, I want to create a generic action and function which does these recurring steps.
E.g. for methods that don't return a value, I have created this:
private readonly Action<string, Action> timedAction = (name, action) =>
{
var sw = Stopwatch.StartNew();
action.Invoke();
trackDuration(name, sw.ElapsedMilliseconds);
};
That can be invoked with timedAction("methodname", () => lib.methodname())
.
I want to do something similar for methods that return a value, but obviously Action
can't be used for that purpose, since it can't return a value.
Is there a way to do this with a generic Func
, so I don't have to declare one for each combination of library method parameters?
Generic functions are functions declared with one or more generic type parameters. They may be methods in a class or struct , or standalone functions. A single generic declaration implicitly declares a family of functions that differ only in the substitution of a different actual type for the generic type parameter.
Functions can create generics by adding the type parameter list <T> before the function parameter list. You can use generics in the same places you'd add any other type in a function (parameter or return types). function method<T>(param: T): T { // ... }
Generics are syntax components of a programming language that can be reused for different types of objects. Typically, generics take the form classes or functions, which take type(s) as a parameter.
In some systems for object-oriented programming such as the Common Lisp Object System (CLOS) and Dylan, a generic function is an entity made up of all methods having the same name. Typically a generic function is an instance of a class that inherits both from function and standard-object.
You can use a generic function like this:
private static TValue FuncHandler<TValue>(string name, Func<TValue> func)
{
var sw = Stopwatch.StartNew();
var result = func();
trackDuration(name, sw.ElapsedMilliseconds);
return result;
}
Call it like this:
var result = FuncHandler("name", () => MyMethod(param1));
Indeed, AOP will buy you more than this sort of tediousness:
https://dotnetfiddle.net/5PLCmM
// Needs to be replicated after Func<T1, TResult>, Func<T1, T2, TResult>, etc, for all the functions arities you'll want to wrap with it
public static TResult Timed<T1, /*T2, etc*/TResult>(out long duration, Func<T1, /*T2, etc*/TResult> func, T1 arg1/*T2 arg2, etc*/)
{
//start timing
var t0 = DateTime.Now;
var result = func(arg1/*, arg2, etc*/);
//end timing
duration = (long)DateTime.Now.Subtract(t0).TotalMilliseconds;
return result;
}
public int Factorial(int n)
{
return n > 0 ? n * Factorial(n - 1) : 1;
}
public int Fibonacci(int n)
{
return n > 1 ? Fibonacci(n - 2) + Fibonacci(n - 1) : n;
}
public static void Main()
{
var program = new Program();
long duration;
var _12bang = Timed(out duration, program.Factorial, 12);
Console.WriteLine("{0}! = {1} in {2} ms", 12, _12bang, duration);
var fib31 = Timed(out duration, program.Fibonacci, 31);
Console.WriteLine("Fib {0} = {1} in {2} ms", 31, fib31, duration);
}
(yes, I know about StopWatch; was just too lazy to put it in there)
'Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With