Reputation: 3563
I have a class called Test
which has a constructor
to accept Action<T>
and the other one accepts Func<T,T>
. Please see the below snippet.
public class Test<T>
{
//constructors
public Test() { }
public Test(Action<T> action) { }
public Test(Func<T, T> action) { }
//methods with same signature of constructor
public void MyMethod1(Action<T> action) { }
public void MyMethod2(Func<T, T> action) { }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Test<string> t1 = new Test<string>(this.MyMethod1);
Test<string> t2 = new Test<string>(this.MyMethod2);
Test<string> t = new Test<string>();
t.MyMethod1(MyMethod1);
t.MyMethod2(MyMethod2);
}
public void MyMethod1(string value) { }
public string MyMethod2(string value) { return string.Empty; }
}
But below lines throws an ambiguous call error
Test<string> t1 = new Test<string>(this.MyMethod1);
Test<string> t2 = new Test<string>(this.MyMethod2);
and the interesting point is, I have two methods with the same signature of my Test
class constructor
which not throwing any ambiguous error
Test<string> t = new Test<string>();
t.MyMethod1(MyMethod1);
t.MyMethod2(MyMethod2);
Could anyone please help me to identify and fix the issue.
Upvotes: 13
Views: 7384
Reputation: 13669
Fact
method / constructor overloading can recognize the correct method by the parameter types but does not include the return type.
Reason
And since in both of the mentioned constructor calls in the question the parameter is of type MethodGroup so the compiler is unable to determine the correct overload. secondly calls to the method are successful as that in not an overloading scenario.
Resolution
here are the possible options to solve the issue
wrapping the method call into an anonymous method call and let the implicit conversion to distinguish themselves.
Test<string> t1 = new Test<string>(s => this.MyMethod1(s));
Test<string> t2 = new Test<string>(s => { return this.MyMethod2(s); });
result
Alternate approach
other option is to explicitly cast the method group
Test<string> t1 = new Test<string>((Action<string>)this.MyMethod1);
Test<string> t2 = new Test<string>((Func<string, string>)this.MyMethod2);
this is bit longer then the first approach if parameters are less
Upvotes: 1
Reputation: 6784
here a working console application sample
class Program
{
static void Main(string[] args)
{
Test<string> t1 = new Test<string>(action: MyMethod1);
Test<string> t2 = new Test<string>(function: MyMethod2);
Test<string> t = new Test<string>();
t.MyMethod1(MyMethod1);
t.MyMethod2(MyMethod2);
}
public static void MyMethod1(string value)
{
Console.WriteLine("my method1 {0}", value);
}
public static string MyMethod2(string value)
{
Console.WriteLine("my method2 {0}", value);
return string.Empty;
}
}
public class Test<T>
{
//constructors
public Test() { }
public Test(Action<T> action)
{
object args = "action";
action.Invoke((T)args); // here you should invoke the method in order to execute it
}
public Test(Func<T, T> function)
{
object args = "function";
function.Invoke((T)args);
}
//methods with same signature of constructor
public void MyMethod1(Action<T> action)
{
object args = "Method 3";
action.Invoke((T)args);
}
public void MyMethod2(Func<T, T> action)
{
object args = "Method 4";
action.Invoke((T)args);
}
}
hope it will help you
regards
Upvotes: 0
Reputation: 2684
The return value of a method is not part of its signature. Only the parameters are considered. Hence, the compiler cannot distinguish between Action<T>
and Func<T,T>
. A detailed explanation and workarounds can be found in this StackOverflow question
Upvotes: 7
Reputation: 267
You can try renaming the parameters for each of your constructors like so:
public class Test<T>
{
public Test() { }
public Test(Action<T> action) { }
public Test(Func<T,T> function) { }
}
So when you instantiate your class you can specify the name of the parameter like so:
var objectWithAction = new Test<string>(action: Method1);
var objectWithFunction = new Test<string>(function: Method2);
Upvotes: 2