0

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);
Cœur
  • 37,241
  • 25
  • 195
  • 267
wolfovercats
  • 490
  • 5
  • 11
  • 1
    Can you provide the error? – kostas ch. Jun 11 '13 at 08:14
  • possible duplicate of [C#: No implicit conversion between 'lambda expression' and 'lambda expression'?](http://stackoverflow.com/questions/564935/c-no-implicit-conversion-between-lambda-expression-and-lambda-expression) and also http://stackoverflow.com/questions/6015747/why-does-funcbool-test-value-f-f-not-compile – Matthew Watson Jun 11 '13 at 08:27

2 Answers2

2

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
Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
1

it's probably the same cause as in this question

if you add "func1 = " to your ternary expressions the compile error should disappear

Community
  • 1
  • 1