How can I assign a Func<> using the conditional ternary operator? [duplicate]
Asked Answered
D

4

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?

Demonic answered 4/9, 2014 at 14:12 Comment(3)
Have you tried adding brackets in various places? e.g. (x => x.SomeProp < 5)Outsole
The compiler probably doesn't know what type the lambda variable x is. Why not put the two expressions in separate variables, then assign one of those to the filter variable using the ternary operator?Continuative
@AlexMDC: Did. Doesn't work.Okra
M
15
var filter = (someBooleanExpressionHere)
   ? new Func<Something, bool>(x => x.SomeProp < 5)
   : x => x.SomeProp >= 5;
Microsporangium answered 4/9, 2014 at 14:15 Comment(4)
Thank you - and I get to use var - kind of - bonus :) !Demonic
@Demonic 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.)Eidson
Yup, hence the 'kind-of'. But at least I don't have to spell out my lambda's signature twice!Demonic
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.Outsize
O
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'

Okra answered 4/9, 2014 at 14:16 Comment(2)
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.Wallsend
True, I first tried with two new Func but the last wasn't necessary.Okra
D
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;
Distance answered 4/9, 2014 at 14:26 Comment(0)
W
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;
Weintraub answered 17/6, 2016 at 9:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.