6

Update

In C#10, this syntax is now valid and the compiler will infer a 'natural type' for a lambda Example here

C# 9 and Earlier

I am aware that Func<>s cannot be implicitly typed directly via the var keyword, although I was rather hoping that I could do the following assignment of a predicate:

Func<Something, bool> filter = (someBooleanExpressionHere)
   ? x => x.SomeProp < 5
   : x => x.SomeProp >= 5;

However, I get the error cannot resolve the symbol, 'SomeProp'

At the moment, I have resorted to the more cumbersome if branch assignment, which doesn't seem as elegant.

Func<Something, bool> filter;
if (someBooleanExpressionHere)
{
    filter = x => x.SomeProp < 5;
}
else
{
    filter = x => x.SomeProp >= 5;
}

Have I missed something, or will I need to stick with the if-branch assignment?

StuartLC
  • 104,537
  • 17
  • 209
  • 285

4 Answers4

14
var filter = (someBooleanExpressionHere)
   ? new Func<Something, bool>(x => x.SomeProp < 5)
   : x => x.SomeProp >= 5;
Lee
  • 142,018
  • 20
  • 234
  • 287
  • Thank you - and I get to use var - kind of - bonus :) ! – StuartLC Sep 04 '14 at 14:18
  • 1
    @StuartLC You get to use `var`, but not without *also* explicitly typing out the type name, so you don't actually have the benefit of `var`. Actually, I'd say there's a reasonable number of folks who would consider your original `if`/`else` more elegant than this. (Personally, I'm divided. I have no real preference for one or the other.) –  Sep 04 '14 at 14:20
  • 2
    Yup, hence the 'kind-of'. But at least I don't have to spell out my lambda's signature *twice*! – StuartLC Sep 04 '14 at 14:21
  • 1
    To further explain why it needs to be done this way, lambdas in C# don't have a type per-se, the type of a lambda is inferred from the usage. In the case of the ternary conditional expression, the compiler wasn't able to infer the lambda type since it would need to know that to infer the type of the conditional expression. Explicitly instantiating a `Func` allows the compiler to figure out the expression type and from there it can infer the type of the other lambda to also be a `Func`. – Kyle Sep 04 '14 at 15:06
3

You should wrap them in a new Func since else it cannot convert the one lamdba to the other:

 Func<Something, bool> filter = (someBooleanExpressionHere)
   ? new Func<Something, bool>(x => x.SomeProp < 5)
   : x => x.SomeProp >= 5
   ;

If you remove the new Func... you will get:

Type of conditional expression cannot be determined because there is no implicit conversion between 'lambda expression' and 'lambda expression'

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
  • The parentheses on the second operand are not strictly necessary, though I agree they are worth adding. Not everyone remembers all the precedence rules, so it improves readability. – Mike Strobel Sep 04 '14 at 14:17
  • True, I first tried with two `new Func` but the last wasn't necessary. – Patrick Hofman Sep 04 '14 at 14:18
1

You can explicitly mention the type as the hint to compiler

var filter = (condition)
    ? (Func<Something, bool>)(x => x.SomeProp < 5)
   : x => x.SomeProp >= 5;
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
Hamlet Hakobyan
  • 32,965
  • 6
  • 52
  • 68
1

If appropriate, you could assign these selectors to static fields.

private static readonly Func<Something, bool> _someFilter = x => x.SomeProp < 5;
private static readonly Func<Something, bool> _someOtherFilter = x => x.SomeProp >= 5;

You can then use them later.

var filter = (someBooleanExpressionHere) ? _someFilter : _someOtherFilter;
Moss
  • 855
  • 1
  • 9
  • 23