The call is ambiguous error for generics methods

Viewed 76

I have struct like this:

public readonly struct SomeStruct<T1, T2>
{
   private readonly object _ref;

   public SomeStruct(T1 value)
   {
     _ref = value;
   }

   public SomeStruct(T2 value)
   {
     _ref = value;
   }

   public SomeStruct<U1, T2> Select<U1>(Func<T1, U1> mapLeft){ // logic... }

   public SomeStruct<T1, U2> Select<U2>(Func<T2, U2> mapRight) { // logic... }
}

And I try to use methods like this:

SomeStruct<int, string> someStruct = new SomeStruct<int, string>("test");

SomeStruct<bool, string> newStruct = someStruct.Select<bool>(x => true);

Or

SomeStruct<int, string> someStruct = new SomeStruct<int, string>(111);

SomeStruct<int, bool> newStruct = someStruct.Select<bool>(x => true);

But I'm getting error: Error The call is ambiguous between the following methods or properties: 'SomeStruct.Select(Func)' and 'SomeStruct.Select(Func)'

2 Answers

You need to specify the types explicitly because the compiler cannot infer the input types for your lambda expression. For example,

SomeStruct<int, string> someStruct = new SomeStruct<int, string>(111);

SomeStruct<int, bool> newStruct = someStruct.Select<bool>((int x) => true);

Why did this happen?

You call someStruct.Select<bool>(x => true). The type of someStruct is SomeStruct<int, string>. So in case of Select<bool> you have these methods for someStruct:

public SomeStruct<bool, string> Select<bool>(Func<int, bool> mapLeft) {}
public SomeStruct<int, bool> Select<bool>(Func<string, bool> mapRight) {}

Thus, your lambda expression x => true can be inferred to Func<int, bool> or Func<string, bool>. That's why you need to specify either int or string for the input parameter to avoid ambiguity.

I think the point is that both of these are valid:

var result1 = new SomeStruct<A, B>().Select<C>((A x) => new C());
var result2 = new SomeStruct<A, B>().Select<C>((B x) => new C());

... and therefore you cannot omit the type specifier for x like this:

var result2 = new SomeStruct<A, B>().Select<C>(x => new C()); // ERROR: CS0121

Also, the generics cannot be resolved based on the type of variable that the result gets assigned to. Although adding the explicit type of the variable to which the result will be assigned does make it unambiguous which version will not be a syntax error in this specific case, C# does not make this inference and therefore doing this doesn't help:

SomeStruct<C, B> resultCB = new SomeStruct<A, B>().Select<C>(x => new C()); // ERROR: CS0121
SomeStruct<A, C> resultAC = new SomeStruct<A, B>().Select<C>(x => new C()); // ERROR: CS0121

I'm not sure why it doesn't make this inference, but it doesn't, so you'll have to explicitly provide the type of x.

Related