I have seen similar questions to this, but they involve different types so I think this is a new question.
Consider the following code:
public void Test(bool value)
{
// The following line provokes a compiler error:
// "Type of conditional expression cannot be determined because there is
// no implicit conversion between 'method group' and 'method group".
Func<bool> test = value ? F : F;
}
public bool F()
{
return false;
}
Now, according to the C# 3.0 Standard,
The second and third operands of the
?: operator control the type of the
conditional expression. Let X and Y be
the types of the second and third
operands. Then,
If X and Y are the same type, then
this is the type of the conditional
Otherwise, if an implicit conversion
(§6.1) exists from X to Y, but not
from Y to X, then Y is the type of the
conditional expression. Otherwise, if
an implicit conversion (§6.1) exists
from Y to X, but not from X to Y, then
X is the type of the conditional
expression. Otherwise, no expression
type can be determined, and a
compile-time error occurs.
It seems to me that in my sample code, X and Y must be of the same type, since they are the selfsame entity, Func. So why does it not compile?
The question was changed significantly, so my original answer is a bit off by now.
However, the problem is essentially the same. I.e. there could be any number of matching delegate declarations for F and since there is no implicit conversion between two identical delegate declarations the type of F cannot be converted to Func<bool>.
Likewise, if you declare
private delegate void X();
private delegate void Y();
private static void Foo() {}
You cannot do
X x = Foo;
Y y = x;
Original answer:
It doesn't work because method groups cannot be assigned to an implicitly typed variable.
var test = Func; doesn't work either.
The reason being that there could be any number of delegate types for Func. E.g. Func matches both of these declarations (in addition to Action)
private delegate void X();
private delegate void Y();
To use implicitly typed variables with method groups, you need to remove the ambiguity by casting.
See archil's answer for a concrete example of one way to fix this. That is, he shows what the corrected code might look like [assuming the delegate you desire to match is Action].
var test = value ? (Action)Func: (Action)Func;
Actually, type of method is expressed by delegate it matches. System.Action that i used to cast methods to, is the delegate with signature returning void and taking no parameters - it matches your Func() method. And now your test will know that it is type of System.Action. Delegates are something like interfaces for methods. Take a look at http://msdn.microsoft.com/en-us/library/ms173171(v=vs.80).aspx
Related
I have this issue:
Func<string,string> transformer = isRTF ? ToRTF : ToHTML;
private string ToRTF(string value) {
//Convert to RTF
return value;
}
private string ToHTML(string value) {
//Convert to HTML
return value;
}
However I am getting this error:
Error 42 Type of conditional expression cannot be determined because there is no implicit conversion between 'method group' and 'method group'
However if I do this:
Func<string, string> transformer = isRTF ? (Func<string, string>) ToRTF : (Func<string, string>) ToHTML;
it works without problems and ReSharper starts complaining that the cast is redundant.
Does anyone know why this is happening?
This is because both sides need a conversion from method group* to Func<string,string>. The compiler has rules to infer the type of one method group from the type given to the other method group, but no rules for situations when both sides of : have method groups.
You can do the conversion only on one side, and let the compiler infer the other side for you. You can also use var for the declaration to avoid repeating the type:
var transformer = isRTF ? new Func<string,string>(ToRTF) : ToHTML;
* Method name used in implicit definitions of delegates are treated as method groups, because a single name can represent multiple overloaded methods.
I know this question is answered and I think the answer is quite good and correct. Nevertheless I encountered this same problem a while ago and what I did to work around this was to return Func from the method itself. Like the following:
private static Func<string,string> A() => (v) => string.Empty;
private static Func<string,string> B() => (v) => "I am not empty =)";
And:
var myFunc = someBool ? A() : B();
I know that this will require to change method's signature and that do not solves the issue directly but at least you do not need to cast.
Hope this helps
What are the precise rules for overload resolution with == between two expressions of delegate type?
Consider the following code (where using System; is needed):
static class ProgramA
{
static void TargetMethod(object obj)
{
}
static void Main()
{
Action<object> instance1 = TargetMethod;
Action<object> instance2 = TargetMethod;
Action<string> a1 = instance1;
Action<Uri> a2 = instance2;
Console.WriteLine((object)a1 == (object)a2);
Console.WriteLine((Delegate)a1 == (Delegate)a2);
Console.WriteLine((Action<object>)a1 == (Action<object>)a2);
Console.WriteLine(a1 == a2); // warning CS0253: Possible unintended reference comparison; to get a value comparison, cast the right hand side to type 'System.Action<string>'
}
}
Explanation:
instance1 and instance2 are two separate instances of the same run-time type, the generic Action<in T> which is contravariant in T. Those instances are distinct but Equals since they the have same targets.
a1 and a2 are the same as instance1 and instance2, but because of the contravariance of Action<in T> there exist implicit reference conversions from Action<object> to each of Action<string> and Action<System.Uri>.
Now, the C# Language Specification has (among other overloads) these operator ==:
bool operator ==(object x, object y); // §7.10.6
bool operator ==(System.Delegate x, System.Delegate y); // §7.10.8
The current Visual C# compiler realizes the first one by simply checking if the references are the same (the IL does not actually call a mscorlib method like object.ReferenceEquals, but that would give the same result), while it realizes the second one by calling Delegate.op_Equality method which looks like a "user-defined" operator inside that assembly even when it is defined by the C# Language Spec, so is maybe not "user-defined" in the sense of the spec(?).
Note that §7.10.8 is a little confusing because it says "Every delegate type implicitly provides the following predefined comparison operator[s]" and then gives the operator with the (System.Delegate, System.Delegate) signature. That is just one operator, not one for "every" delegate type? This seems important for my question.
It is not surprising that the three first WriteLine write False, True and True, respectively, given what I said above.
Question: But why does the fourth WriteLine lead to the (object, object) overload being used?
There does exist an implicit reference conversion from Action<> (or any other delegate type) to System.Delegate, so why can't that be used here? Overload resolution should prefer that over the (object, object) option.
Of course, there are no implicit conversions between Action<string> and Action<Uri>, but why is that relevant? If I create my own class MyBaseClass containing a user-defined operator ==(MyBaseClass x, MyBaseClass y) and I create two unrelated deriving classes, then my == operator will still be used (left and right operand not convertible to each other but both convertible to MyBaseClass).
Just for completeness, here is the analogous example with covariance (Func<out TResult>) instead of contravariance:
static class ProgramF
{
static string TargetMethod()
{
return "dummy";
}
static void Main()
{
Func<string> instance1 = TargetMethod;
Func<string> instance2 = TargetMethod;
Func<ICloneable> f1 = instance1;
Func<IConvertible> f2 = instance2;
Console.WriteLine((object)f1 == (object)f2);
Console.WriteLine((Delegate)f1 == (Delegate)f2);
Console.WriteLine((Func<string>)f1 == (Func<string>)f2);
Console.WriteLine(f1 == f2); // warning CS0253: Possible unintended reference comparison; to get a value comparison, cast the right hand side to type 'System.Func<System.ICloneable>'
}
}
A question related to my question above is, where in the C# Language Specification does it say that this shall be illegal:
Func<string> g1 = ...;
Func<Uri> g2 = ...;
Console.WriteLine(g1 == g2); // error CS0019: Operator '==' cannot be applied to operands of type 'System.Func<string>' and 'System.Func<System.Uri>'
I can see that the compiler figured out that no type can ever inherit from both string and Uri (unlike the pair ICloneable and IConvertible), and so this (if it were legal) could only become true if both variables were null, but where does it say that I am not allowed to do this? In this case it would not matter if the compiler chose operator ==(object, object) or operator ==(Delegate, Delegate) since, as I said, it comes down to checking if both are null references, and both overloads do that in the same way.
Question: But why does the fourth WriteLine lead to the (object, object) overload being used?
Because it's the only choice for the compiler :-)
Cannot apply operator '==' to operands of type 'System.Func<System.ICloneable>' and 'System.Func<System.IConvertable>'
candidates are:
bool==(System.Delegate, System.Delegate)
bool==(System.Func<System.ICloneable>, System.Func<System.ICloneable>)
bool==(System.Func<System.IConvertable>, System.Func<System.IConvertable>)
so using your (object, object) is the best choice the compiler finds.
same for the Actions
Cannot apply operator '==' to operands of type 'System.Action<string>' and 'System.Action<System.Uri>'
candidates are:
bool==(System.Delegate, System.Delegate)
bool==(System.Action<string>, System.Action<string>)
bool==(System.Action<System.Uri>, System.Action<System.Uri>)
So i'm not really convinced when its safe to say that a method group conversion occured.
We have this multicast delegate from a previous post:
public partial class MainPage : PhoneApplicationPage
{
public delegate void MyDelegate(int a, int b);
// Constructor
public MainPage()
{
InitializeComponent();
MyDelegate myDel = new MyDelegate(AddNumbers);
myDel += new MyDelegate(MultiplyNumbers);
myDel(10, 20);
}
public void AddNumbers(int x, int y)
{
int sum = x + y;
MessageBox.Show(sum.ToString());
}
public void MultiplyNumbers(int x, int y)
{
int mul = x * y;
MessageBox.Show(mul.ToString());
}
}
I say that a method group conversion only occurs when we have assigned a method thats overloaded, and at least one overload matches the delegate. In this case there is no method group conversion.
a fellow programmer says that if you don't think MyDelegate myDel = AddNumbers; (with names referring to the question) is a method group conversion, then what would it be then?
The C# Language Specification: An implicit conversion (§6.1) exists from a method group (§7.1) to a compatible delegate type. Given a delegate type D and an expression E that is classified as a method group, an implicit conversion exists from E to D if [...]
So wich point of view is correct?
I say that a method group conversion only occurs when we have assigned a method thats overloaded
Nope, there's no requirement of overloading (by multiple methods) for method group conversions.
Any time you've got just a method name, or a method name qualified with a target (e.g. MultiplyNumbers or foo.MultiplyNumbers), that's a method group. If you're converting that to a delegate instance, that's a method group conversion.
EDIT: The section of the spec which is causing problems is this, in 7.1:
A method group, which is a set of overloaded methods resulting from a member lookup (7.4).
That "set of overloaded methods" can be a set of size 1 - it's still a method group.
This is backed up by 7.6.5.1 (Method Invocations) - emphasis mine:
For a method invocation, the primary-expression of the invocation-expression must be a method group. The method group identifies the one method to invoke or the set of overloaded methods from which to choose a specific method to invoke.
That makes it clear that a method group with one element is a meaningful concept.
Method group conversion has nothing to do with overloads. Don't get confused by "method group". It doesn't mean that it has to be more than one.
You have assigned a method in which at least one overload matches the delegate - it just so happens there is only one overload. The point of the "conversion" is simply that the compiler can infer the new MyDelegate bit rather than you needing to explicitly construct it.
Delegate is clear to understand
delegate int del(int i);
but why can we use
del myDelegate = x => x * x;
Questions here:
How can I assure x is int type in the lambda expresison?
How can I know lambda expression return a int?
C# compiler is smart enough to implicitly figure out the type of x on the left side of => from the context. Since it knows that you are assigning the lambda to a variable of type del, the compiler knows that x is an int.
As far as the return type goes, the compiler knows that x is an int, therefore the type of the x * x expression must also be int. That's how the compiler knows the return type of the lambda.
Note that the same code would not have compiled without the exact type of myDelegate specified:
// This does not compile!
var myDelegate = x => x*x;
Because for you to have x, you had to give it a type. It will detect this type rather than making you tell it over and over what type it is.
Right now you're letting the compiler determine what the lamdba expression is doing. You can sublclass using Action and Func
Actions return type is void while Func's return type is whatever you specify as the last type parameter. You can specify additional inputs in both
Func<in, in2, in3, output>
For returning an int
var f = new Func<int, int>(x => x*x);
When assigning a method to a Func-type, I get the compilation error Type of conditional expression cannot be determined because there is no implicit conversion between 'method group' and 'method group'.
This only happens with the ? : operator. The code:
public class Test
{
public static string One(int value)
{
value += 1;
return value.ToString();
}
public static string Two(int value)
{
value += 2;
return value.ToString();
}
public void Testing(bool which)
{
// This works
Func<int, string> actionWorks;
if (which) actionWorks = One; else actionWorks = Two;
// Compilation error on the part "One : Two"
Func<int, string> action = which ? One : Two;
}
}
I found some information about co- and contravariance, but I don't see how that applies to the situation above. Why doesn't this work?
You need to explicitly provide the signature of at least one method group. However, after doing it the compiler will allow you to declare action as an implicitly-typed local:
var action = which ? (Func<int, string>)One : Two;
The reason this happens is that the return type of operator ?: is not deduced based on what you are trying to assign it to, but based on the types of the two expressions. If the types are the same or there is an implicit conversion between them, the compiler deduces the return type successfully; otherwise, it complains that there is no conversion.
When you directly assign a function to a delegate, the compiler will convert the function to the required delegate type if it matches the signature.
However, when you're using the ?: operator, as far as the compiler is concerned you're not directly assigning to a delegate, so it doesn't know what type to use for One and Two, and so it thinks the two types used in the ?: operator don't match.
The only fix is making the conversion explicit:
Func<int, string> action = which ? new Func<int, string>(One) : new Func<int, string>(Two);
Jon's solution works
var action = which ? (Func<int, string>)One : Two;
Another alternative is to create a new anonymous delegate yourself. This is semantically lil' different but I think this can be useful too.
Func<int, string> action = x => which ? One(x) : Two(x);
I find this lil' more elegant, though not as short..