c# - Compiler Ambiguous invocation error - anonymous method and method group with Func<> or Action -
i have scenario want use method group syntax rather anonymous methods (or lambda syntax) calling function.
the function has 2 overloads, 1 takes action
, other takes func<string>
.
i can happily call 2 overloads using anonymous methods (or lambda syntax), compiler error of ambiguous invocation if use method group syntax. can workaround explicit casting action
or func<string>
, don't think should necessary.
can explain why explicit casts should required.
code sample below.
class program { static void main(string[] args) { classwithsimplemethods classwithsimplemethods = new classwithsimplemethods(); classwithdelegatemethods classwithdelegatemethods = new classwithdelegatemethods(); // these both compile (lambda syntax) classwithdelegatemethods.method(() => classwithsimplemethods.getstring()); classwithdelegatemethods.method(() => classwithsimplemethods.donothing()); // these compile (method group explicit cast) classwithdelegatemethods.method((func<string>)classwithsimplemethods.getstring); classwithdelegatemethods.method((action)classwithsimplemethods.donothing); // these both error "ambiguous invocation" (method group) classwithdelegatemethods.method(classwithsimplemethods.getstring); classwithdelegatemethods.method(classwithsimplemethods.donothing); } } class classwithdelegatemethods { public void method(func<string> func) { /* */ } public void method(action action) { /* */ } } class classwithsimplemethods { public string getstring() { return ""; } public void donothing() { } }
first off, let me jon's answer correct. 1 of hairiest parts of spec, on jon diving head first.
second, let me line:
an implicit conversion exists method group compatible delegate type
(emphasis added) misleading , unfortunate. i'll have talk mads getting word "compatible" removed here.
the reason misleading , unfortunate because looks calling out section 15.2, "delegate compatibility". section 15.2 described compatibility relationship between methods , delegate types, question of convertibility of method groups , delegate types, different.
now we've got out of way, can walk through section 6.6 of spec , see get.
to overload resolution need first determine overloads applicable candidates. candidate applicable if arguments implicitly convertible formal parameter types. consider simplified version of program:
class program { delegate void d1(); delegate string d2(); static string x() { return null; } static void y(d1 d1) {} static void y(d2 d2) {} static void main() { y(x); } }
so let's go through line line.
an implicit conversion exists method group compatible delegate type.
i've discussed how word "compatible" unfortunate here. moving on. wondering when doing overload resolution on y(x), method group x convert d1? convert d2?
given delegate type d , expression e classified method group, implicit conversion exists e d if e contains @ least 1 method applicable [...] argument list constructed use of parameter types , modifiers of d, described in following.
so far good. x might contain method applicable argument lists of d1 or d2.
the compile-time application of conversion method group e delegate type d described in following.
this line doesn't interesting.
note existence of implicit conversion e d not guarantee compile-time application of conversion succeed without error.
this line fascinating. means there implicit conversions exist, subject being turned errors! bizarre rule of c#. digress moment, here's example:
void q(expression<func<string>> f){} string m(int x) { ... } ... int y = 123; q(()=>m(y++));
an increment operation illegal in expression tree. however, lambda still convertible expression tree type, though if conversion ever used, error! principle here might want change rules of can go in expression tree later; changing rules should not change the type system rules. want force make programs unambiguous now, when change rules expression trees in future make them better, we don't introduce breaking changes in overload resolution.
anyway, example of sort of bizarre rule. conversion can exist purposes of overload resolution, error use. though in fact, not situation in here.
moving on:
a single method m selected corresponding method invocation of form e(a) [...] argument list list of expressions, each classified variable [...] of corresponding parameter in formal-parameter-list of d.
ok. overload resolution on x respect d1. formal parameter list of d1 empty, overload resolution on x() , joy, find method "string x()" works. similarly, formal parameter list of d2 empty. again, find "string x()" method works here too.
the principle here determining method group convertibility requires selecting method method group using overload resolution, , overload resolution not consider return types.
if algorithm [...] produces error, compile-time error occurs. otherwise algorithm produces single best method m having same number of parameters d , conversion considered exist.
there 1 method in method group x, must best. we've proven conversion exists x d1 , x d2.
now, line relevant?
the selected method m must compatible delegate type d, or otherwise, compile-time error occurs.
actually, no, not in program. never far activating line. because, remember, we're doing here trying overload resolution on y(x). have 2 candidates y(d1) , y(d2). both applicable. better? nowhere in specification describe betterness between these 2 possible conversions.
now, 1 argue valid conversion better 1 produces error. saying, in case, overload resolution consider return types, want avoid. question principle better: (1) maintain invariant overload resolution not consider return types, or (2) try pick conversion know work on 1 know not?
this judgment call. lambdas, do consider return type in these sorts of conversions, in section 7.4.3.3:
e anonymous function, t1 , t2 delegate types or expression tree types identical parameter lists, inferred return type x exists e in context of parameter list, , 1 of following holds:
t1 has return type y1, , t2 has return type y2, , conversion x y1 better conversion x y2
t1 has return type y, , t2 void returning
it unfortunate method group conversions , lambda conversions inconsistent in respect. however, can live it.
anyway, have no "betterness" rule determine conversion better, x d1 or x d2. therefore give ambiguity error on resolution of y(x).
Comments
Post a Comment