2

I ran into an odd compilation issue while I was implementing a simple timing utility class.

I implemented the following class that would allow wrapping calls to functions with timing related measurement information.

public static class TimeMeasument
{
    public static void LogRunTime<T>(Action<T> func, T arg)
    {
        Stopwatch timer = Stopwatch.StartNew();
        try { func(arg); }
        finally { Console.WriteLine("Elapsed time {0} ms", timer.ElapsedMilliseconds); }
    }

    public static TResult LogRunTime<TResult, T>(Func<T, TResult> func, T arg)
    {
        Stopwatch timer = Stopwatch.StartNew();
        try { return func(arg); }
        finally { Console.WriteLine("Elapsed time {0} ms", timer.ElapsedMilliseconds); }
    }
}

The problem I have is that when I went to use the function I received an Ambiguous function call compiler error when trying to call functions that have a return value.

// Example function
string SayHello(string name)  { return "Hello " + name; }

// Compiler error 
// Ambiguous call between the following methods
// LogRunTime<T>(Action<T> func, T arg)
// and LogRunTime<TResult, T>(Func<T,TResult> func, T arg)
//-----------------------------------------------------------------
string x = TimeMeasument.LogRunTime(SayHello, "Joe");

I need to explicitly create a Func<T,U> for the function to remove the ambiguity.

// Compiles fine
Func<string, string> func = SayHello;
string s = TimeMeasument.LogRunTime(func, "Joe");

I was wondering why the Action<T> overload is being considered by the compiler as an option. I know that the generic type parameter for Action is satisfied by the second argument passed to LogRunTime but the function SayHello is not convertible to an Action. Doing so will result in the following error.

// Compiler error
// SayHello(string) has the wrong return type
//-------------------------------
Action<string> action = SayHello;

Can anyone shed some light on why the Action<T> overload is considered as a valid target?

Is there any other way of getting around this issue without explicitly creating/casting each function call?

NickC
  • 385
  • 1
  • 10
  • From the linked duplicate answer it looks like the best solution to address this compiler error is to pass a lambda functions instead. Like this: `TimeMeasument.LogRunTime(y => SayHello(y), "Joe");` – NickC Mar 10 '15 at 20:17

0 Answers0