Reputation: 500
This one's got me flummoxed, so I thought I'd ask here in the hope that a C# guru can explain it to me.
Why does this code generate an error?
Func<IEnumerable<Item>, IEnumerable<Item>, IEqualityComparer<Item>, IEnumerable<Item>> func = strict ?
(first, second, comparer) => first.Intersect(second, comparer) :
(first, second, comparer) => first.Union(second, comparer);
while this one doesn't:
Func<IEnumerable<Item>, IEnumerable<Item>, IEqualityComparer<Item>, IEnumerable<Item>> func1;
if (strict)
func1 = (first, second, comparer) => first.Intersect(second, comparer);
else
func1 = (first, second, comparer) => first.Union(second, comparer);
Upvotes: 0
Views: 654
Reputation: 61950
A lambda arrow =>
like
(first, second, comparer) => first.Intersect(second, comparer)
does not possess a type in itself. It is implicitly convertible to all delegate types that match the signature and return type, though. It is also (with some exceptions) convertible to Expression<Del>
where Del
is such a delegate.
When you assign the lambda arrow directly to the func1
variable, the compiler knows exactly what delegate type to convert into. So that works (you second example).
In the first example:
strict ?
(first, second, comparer) => first.Intersect(second, comparer) :
(first, second, comparer) => first.Union(second, comparer)
(before we even come to the assignment to func
) the compiler first has to find the best common type of the two types on each side of the colon :
. But a lambda arrow doesn't have a type, as I said, so that fails. It would work if you said:
strict ?
(Func<IEnumerable<Item>, IEnumerable<Item>, IEqualityComparer<Item>, IEnumerable<Item>>)((first, second, comparer) => first.Intersect(second, comparer)) :
(Func<IEnumerable<Item>, IEnumerable<Item>, IEqualityComparer<Item>, IEnumerable<Item>>)((first, second, comparer) => first.Union(second, comparer))
but that is ugly, of course. (Actually, you only have to cast one of the two lambdas to give it a type, the other one will get the same type automatically then.)
Addition:
An analogous thing happens for the null
keyword which also doesn't have a type by itself but is implicitly convertible to a lot of types (like string
). So this works:
string myString1 = null;
while these don't:
var myString2 = null; // need to cast null to a type, to use var
string myString3 = strict ? null : null; // cast at least one null, to use ternary op
Upvotes: 2
Reputation:
it's probably the same cause as in this question
if you add "func1 = " to your ternary expressions the compile error should disappear
Upvotes: 1