Reputation: 27615
I would like to have a "generic" - that is, a method with a single signature if possible - instead of this rather copy/paste code below.
My goal is to "wrap" methods from a third party DLL with a Spy Double
int spy(Func<int> method)
{
methodCalls.Add(method.Method.Name);
return method.Invoke();
}
int spy(Func<string, int> method, string arg)
{
methodCalls.Add(method.Method.Name);
return method.Invoke(arg);
}
private int spy(Func<int, int> method, int arg)
{
methodCalls.Add(method.Method.Name);
return method.Invoke(arg);
}
You see the problem: I have almost identical method blocks... Is there a way to avoid this and still accomplish the desired behavior?
Upvotes: 1
Views: 119
Reputation: 8318
Based on your primary aim
to have a "generic" - that is, a method with a single signature if possible instead of this rather copy/paste code below.
You can try following
object SpyUniversal(Delegate method, object[] args)
{
methodCalls.Add(method.Method.Name);
return method.Method.Invoke(null, args);
}
Notice that you are losing compile-time type-safety as it was mentioned.
Upvotes: 1
Reputation: 236328
First of all you need generic methods for Func
and Action
delegates which you want to spy. You need these methods for nice strongly-typed API. You also need a private generic method which accepts a Delegate
and a list of arguments. This method will do invoking and logging:
public TResult Spy<TResult> (Func<TResult> method)
{
return Spy<TResult>((Delegate)method);
}
public TResult Spy<T1, TResult> (Func<T1, TResult> method, T1 arg1)
{
return Spy<TResult>((Delegate)method, arg1);
}
private TResult Spy<TResult> (Delegate method, params object[] args)
{
methodCalls.Add(method.Method.Name);
return (TResult)method.Method.Invoke(method.Target, args);
}
Now you can pass any methods with zero or one argument, execute them and log method name without any duplication.
Upvotes: 2
Reputation: 1503649
Well you could start off by making them generic:
public TResult Spy<TResult>(Func<TResult> method)
{
methodCalls.Add(method.Method.Name);
return method();
}
public TResult Spy<TArg, TResult>(Func<TArg, TResult> method, TArg arg)
{
methodCalls.Add(method.Method.Name);
return method(arg);
}
public TResult Spy<TArg1, TArg2, TResult>
(Func<TArg1, TArg2, TResult> method, TArg1 arg1, TArg2 arg2)
{
methodCalls.Add(method.Method.Name);
return method(arg1, arg2);
}
...
That at least means you only need as many overloads as the maximum number of parameters you want to handle. You won't easily be able to do better than that without losing compile-time type-safety.
Upvotes: 2