A simple trick is to just use the most simple Func<T>
which returns a type, and instead of passing the other types as type arguments to the generic, you use a closure to capture them from the surrounding context.
For example:
int SomeFunctionWith3Args(int arg1, int arg2, int arg3) { ... }
.
int[] arg = new int[] { 1, 2, 3 };
var x = MeasureThis<int>(() => SomeFunctionWith3Args(arg[0], arg[1], arg[2]));
If you're not familiar with how this kind of closure works, it basically creates a new type which houses the arguments you capture as fields, and implements the lambda as a method of the class - then replaces the call site with an instantiation of the class and a call to the method. For example, the above is (conceptually) equivalent to:
int[] arg = new int[] { 1, 2, 3 };
var closure = new TheClosure();
closure._captured = arg;
var x = MeasureThis<int>(closure.TheLambda());
where
class TheClosure {
public int[] _captured;
public int TheLambda() {
return SomeFunctionWith3Args(_captured[0], _captured[1], _captured[2]);
}
}