views:

227

answers:

5

I have an overloaded utility method called CheckDuration with following function signatures.

    private static Action<int> CheckDuration(Action action)
    private static Action<int> CheckDuration<T>(Action<T> action, T arg)

Basically CheckDuration prints on console how long it took to run a method.

Now, I would like to check the duration of a method that takes 2 argument.
So I would have to create another overloaded CheckDuration with following method signature.

    private static Action<int> CheckDuration<T, U>(
        Action<T, U> action, T arg1, U arg2)

Is there a way to handle this more gracefully?
I was thinking about something like

    private static Action<int> CheckDuration<params T>(
      Action<params T> action, params T arg)

, which obviously doesn't work.

[UPDATE] I will leave this question open for now to see if anyone has come up with a work-around for this kind of problem.

+5  A: 

Unfortunately what you have already is about as clean as its going to get. C# does not support the use of params for generic type parameters and supporting something like that would be very difficult. Your original solution is good and is in the spirit of similiar delegates in the BCL like the Action delegates which have overloaded definitions to take different numbers of arguments.

Andrew Hare
Out of curiosity, can you please tell me why it would be very difficult? I am just curious :)
Joan Venge
A: 

No, there's no way. However, I suppose that for this 'CheckDuration' to work, both T and U should either implement some well-defined interface or inherit from one base class (or otherwise you'll be doing lots of reflection, which kinda defeats the purpose of using generics). Thus, consider:

Action<int> CheckDuration<T>(Action<T> action, params T[] args)
    where T : ISupportCheckDuration

And you'll be able to stuff anything that's ISupportCheckDuration-compatible in there.

Anton Gogolev
Unfortunately with this example you are forced to have one type as all the args will be of type T.
Andrew Hare
No, they should all implement ISupportCheckForDuration or whatever. These can be absolutely different types as long as they satisfy this condition.
Anton Gogolev
Anton Goglev: I was thinking about passing "Console.WriteLine", but since it expects "params object[]", I was not able to use it for that case.
Sung Meister
@Anton Gogolev: I see what you mean now, my mistake.
Andrew Hare
A: 

Have a look at PostSharp:

http://www.postsharp.org/

I think it could help you. Look at the trace example. I think you could adapt it to perform your timing. Then you could just add an attribute to any method you need to time, regardless of the number of arguments it takes.

Chris

Chris Dunaway
+2  A: 

You can't do it quite like you want but you can achieve the same goal:

public static class MethodTimer
{
    public static long Run(Action action)
    {
        var sw = System.Diagnostics.Stopwatch.StartNew();
        action();
        sw.Stop();
        return sw.ElapsedMilliseconds;
    }
}
class Program
{
    static void Main(string[] args)
    {
        long time = MethodTimer.Run(() => File.Open(@"c:\test.txt", 
            FileMode.CreateNew));
        Console.WriteLine(time);
        Console.ReadLine();
    }
}

You could even define this as an extension method so your code might be:

        Action act = () => File.Open(@"c:\test.txt", FileMode.CreateNew);
        time=act.Time();

This method would be defined as:

public static class MethodTimer
    {
        public static long Time(this Action action)
        {
            var sw = System.Diagnostics.Stopwatch.StartNew();
            action();
            sw.Stop();
            return sw.ElapsedMilliseconds;
        }
    }

Edit

You do not need to define any new methods this approach is using a closure around the method that you want to time. So:

MethodTimer.Time(()=> File.Open("",FileMode.Open);
MethodTimer.Time(()=> myObject.TestMethod(123,1231,"another param"));

And so on and so on.

JoshBerke
It seems like even with your Extension method approach, I would have to create a new method per each Action declaration...
Sung Meister
No, you just need the one for Action. The closure binds the method arguments, so that the Action never needs to pass them to the method.
munificent
A: 

Not possible with generics, but with C++/CLI's variadic templates (when it gets support for them), you can do it.

codekaizen
I am not familiar with C++ templates but if the worse comes to worst, I would check it out.
Sung Meister