Generally, when using the conditional operator, here's the syntax:
int x = 6;
int y = x == 6 ? 5 : 9;
Nothing fancy, pretty straight forward.
Now, let's try to use this when assigning a Lambda to a Func type. Let me explain:
Func<Order, bool> predicate = id == null
? p => p.EmployeeID == null
: p => p.EmployeeID == id;
That's the same syntax, and should work? Right? For some reason that doesn't. The compiler gives this nice cryptic message:
Error 1 Type of conditional expression cannot be determined because there is no implicit conversion between 'lambda expression' and 'lambda expression'
I then went ahead and changed the syntax and this way it did work:
Func<Order, bool> predicate = id == null
? predicate = p => p.EmployeeID == null
: predicate = p => p.EmployeeID == id;
I'm just curious as to why it doesn't work the first way?
(Side note: I ended up not needing this code, as I found out that when comparing an int value against null, you just use object.Equals)
You can convert a lambda expression to a particular target delegate type, but in order to determine the type of the conditional expression, the compiler needs to know the type of each of the second and third operands. While they're both just "lambda expression" there's no conversion from one to the other, so the compiler can't do anything useful.
I wouldn't suggest using an assignment, however - a cast is more obvious:
Func<Order, bool> predicate = id == null
? (Func<Order, bool>) (p => p.EmployeeID == null)
: p => p.EmployeeID == id;
Note that you only need to provide it for one operand, so the compiler can perform the conversion from the other lambda expression.
The C# compiler cannot infer the type of the created lambda expression because it processes the ternary first and then the assignment. you could also do:
Func<Order, bool> predicate =
id == null ?
new Func<Order,bool>(p => p.EmployeeID == null) :
new Func<Order,bool>(p => p.EmployeeID == id);
but that just sucks,
you could also try
Func<Order, bool> predicate =
id == null ?
(Order p) => p.EmployeeID == null :
(Order p) => p.EmployeeID == id;
Let me have my own example since I had the same problem, too (with the hope that the example be helpful for others):
My Find method is generic method that gets Expression<Func<T, bool>> as predicate and gives List<T> as output.
I wanted to find countries, but I need all of them if language list was empty, and filtered list, if language list was filled.
First I used the Code as below:
var countries=
Find(languages.Any()
? (country => languages.Contains(country.Language))
: (country => true));
But exactly I get the error :there is no implicit conversion between lambda expression and lambda expression.
The problem was that, we have just two lambda expressions here, and nothing else, for example, what is country => true exactly?? We have to determine the type of at least one of lambda expressions. If just of one of the expressions be determined, then the error will be omitted. But for make the code more readable, I extracted both lambda expressions, and used the variable instead, as below:
Expression<Func<Country, bool>> getAllPredicate = country => true;
Expression<Func<Country, bool>> getCountriesByLanguagePredicate = country => languages.Contains(country.Language);
var countries= Find(languages.Any()
? getCountriesByLanguagePredicate
: getAllPredicate);
I emphasize that, if I just determined one of the expression's type, the error will be fixed.
Just an update - in C# 10, it IS now possible for the compiler to infer the 'natural type' of a lambda, provided that the input type(s) are provided, e.g.
var evenFilter = (int i) => i % 2 == 0; // evenFilter inferred as `Func<int, bool>`
This also means that 0 input Funcs and Actions can be inferred:
var zeroInputFunc = () => 44 % 2 == 0;
var myAction = () => {Console.WriteLine("Foo");};
However, this won't work:
var filter = i => i % 2 == 0; << Error: The delegate type could not be inferred
As a result, it is now possible to do what the OP originally wanted to do, provided that at least the input types are provided, e.g.
Func<int, bool> myPredicate = selectorFlag
? i => i % 2 == 0
: i => i % 2 == 1;
However, this still isn't permitted:
var myPredicate = selectorFlag
? (int i) => i % 2 == 0
: (int i) => i % 2 == 1;
Error : no implicit conversion between 'lambda expression' and 'lambda expression'
Related
This question already has answers here:
Why doesn't the C# ternary operator work with delegates?
(2 answers)
Closed 4 years ago.
I have the following code in an if else statement (c#).
if (!string.IsNullOrEmpty(ParentKey))
{
Build(x => x.ParentKey == ParentKey);
}
else
{
Build(x => x.Url == Request.Url.GetLeftPart(UriPartial.Path));
}
However, I would have preferred to use a condition expression like this:
var r = !string.IsNullOrEmpty(ParentKey)
? 100
: 1000;
Normally, this wouldn't be an issue but the var is a Func<SiloNode, bool> meaning the expression would look like this:
Func<SiloNode, bool> predicate = !string.IsNullOrEmpty(ParentKey)
? x => x.ParentKey == ParentKey
: x => x.Url == Request.Url.GetLeftPart(UriPartial.Path);
Unsurprisingly, the code above gives me a syntax error but I'm not sure whether its because I'm using the wrong syntax or it is just not possible.
Anyone shed any light?
A lambda is just a lambda, and your two lambdas don't necessarily correspond to a Func object (even though the signatures match).
You can actually cast one (or both) of those lambdas into the appropriate Func type, and then the ?: operator will work.
Func<SiloNode, bool> predicate = !string.IsNullOrEmpty(ParentKey)
? (Func<SiloNode, bool>)(x => x.ParentKey == ParentKey)
: x => x.Url == Request.Url.GetLeftPart(UriPartial.Path);
I know have this simple lambda query(not sure if this one called a query)
var person = db.People.Where(a => a.PersonId == id).FirstOrDefault();
I have a question because i don't know anything about lambda. What is the purpose of => and what is the value of that in linq if it is converted to linq?.
For my basic knowledge this might the converted linq query
var person = (from p in db.Person where p.PersonId == id select p).FirstOrDefault();
right?
The =>, which can be read as maps to or is mapped to belongs to the syntax of labda expressions. Informally the syntax of lambda expressions is
(arg_1, arg_2, ..., arg_n) => rhs,
where (arg-1, arg_2, ..., arg_n) is the list of arguments; if there is one argument, the list (arg1) can be abbreviated to arg1. rhs is either an expression of the desired return type, such as in
x => x * x
or a compound statement returning the desired type as follows.
x =>
{
return x * x;
}
The arguments and return type of the lambda expression are not explicitly defined but deduced at compile time. In total,
a => a.PersonId == id
defines function which maps a person a to a boolean value which is generated by evaluating a.PersonId == id, which means that the return value is true if and only if the person's PersonId is equal to id.
The => is the lambda operator, and is part of the syntax for lambda expressions.
On the left of the => are the input parameters for the expression on the right of =>
a=> a.PersonId == id
is like a function that takes a person object and an Id and returns a boolean, i.e.
bool CheckIfIdIsEqual(Person a, int id) {
return a.PersonId == id;
}
Yes, you are right. The expressions where we use => operator are called lambda expressions.
In the lambda calculus, we describe these patterns as tiny functions. In the C# language, we use lambda functions and the => operator to transform data.
var person = db.People.Where(a => a.PersonId == id).FirstOrDefault();
In the above code, we access all the values or data from db.People using the variable a
For more information you can refer:
1.Expression Lambdas
2.C Sharp Lambda Expression
3.Lambda Expression
Duplicate
I can do this:
Func<CategorySummary, decimal> orderByFunc;
if (orderBy == OrderProductsByProperty.Speed)
orderByFunc = x => x.Speed;
else
orderByFunc = x => x.Price;
Why can't I do this:
Func<CategorySummary, decimal> orderByFunc = (orderBy == OrderProductsByProperty.Speed) ? x => x.Speed : x => x.Price;
The 'type inference' on the conditional operator is not quite good enough, I get a message like
Type of conditional expression cannot
be determined because there is no
implicit conversion between 'lambda
expression' and 'lambda expression'
you can always just be explicit on the right-hand-side, a la
var o = true ? new Func<int,int>(x => 0) : new Func<int,int>(x => 1);
In any case it's just a minor annoyance regarding how the types of lambdas, type inference, and the conditional operator interact.
Just cast the lambda's to Func<CategorySummary, decimal> and it will work
An alternative to the suggestions so far - move the conditional inside the lambda expression:
Func<CategorySummary, decimal> orderByFunc =
x => (orderBy == OrderProductsByProperty.Speed) ? x.Speed : x.Price;
It may not be suitable in all situations (and it does mean that the check is performed on every invocation) but sometimes it could be useful.
EDIT: As Eric points out, the two are not equivalent. Here's a quick example of how they differ (using explicit casting to get the conditional to work where the operands are lambdas):
using System;
class Test
{
static void Main()
{
bool likesCheese = false;
Action outerConditional = likesCheese
? (Action) (() => Console.WriteLine("Outer: I like cheese"))
: (Action) (() => Console.WriteLine("Outer: I hate cheese"));
Action innerConditional = () =>
Console.WriteLine (likesCheese ? "Inner: I like cheese"
: "Inner: I hate cheese");
Console.WriteLine("Before change...");
outerConditional();
innerConditional();
likesCheese = true;
Console.WriteLine("After change...");
outerConditional();
innerConditional();
}
}
Results:
Before change...
Outer: I hate cheese
Inner: I hate cheese
After change...
Outer: I hate cheese
Inner: I like cheese
As you can see, the change to the value of likesCheese only affects the version which has the conditional operator inside the lambda expression. Sometimes this is desirable, sometimes not... but you definitely need to be aware of it.
It's enough to cast only one resulting operand to a target type:
Action showResult = true
? (Action)(() => Console.Write("Hello!"))
: () => Console.Write("");
It was a little unexpected, but this is how compiler works. And when I think about it, it makes sense now.
So i have a method
public IPagedList<MyObject> GetAll<T>(Expression<Func<MyObject, T>>? orderBy,
int pageNumber = 1, int pageSize = 10)
{
return dataContext.MyObjects
.OrderBy(orderBy.HasValue ? orderBy.Value : <WHAT GOES HERE?>)
.ToPagedList<MyObject>(pageNumber, pageSize);
}
My goal is to have the orderBy parameter optional, if orderBy is null then default the order to the property MyObject.Id.
I've tried .OrderBy(orderBy.Hasvalue ? orderBy.Value : x => x.Id) but getting this error:
Type of conditional expression cannot be determined because there is no implicit conversion between 'System.Func<MyObject, T>' and 'lambda expression'
What am I doing wrong?
Thanks!
There are a few problems with your code
Expression<TDelegate> is a class, so it's nullable already; you can simply test if orderBy == null. Nullable<T> has a generic constraint that T must be a struct, so Expression<Func<MyObject, T>>? won't compile.
Next you'll have the problem that because the type T isn't bound inside the method, but x.Id is. In other words, you won't be able to create use the conditional operator to choose between a value of Expression<Func<MyObject, T>> and Expression<Func<MyObject, int>> (assuming that Id is an int) while still maintaining type information to pass to the OrderBy method.
The solution is to use something along these lines:
public IPagedList<MyObject> GetAll<T>(Expression<Func<MyObject, T>> orderBy,
int pageNumber = 1, int pageSize = 10)
{
IQueryable<MyObject> objects = dataContext.MyObjects;
objects = (orderBy != null) ? objects.OrderBy(orderBy)
: objects.OrderBy(x => x.Id);
return objects.ToPagedList<MyObject>(pageNumber, pageSize);
}
The conditional operator works in this code because regardless of what you pass to OrderBy the return type will be the same, IQueryable<MyObject>.
Note also that you can't simply pass in a null value for orderBy, because T can't be inferred. You'd have to call it like this:
var results = MyClass.GetAll<int>(null);
Ultimately, you'd probably be better off creating two overloads, one that accepts an orderBy expression, and one that doesn't.
Generally, when using the conditional operator, here's the syntax:
int x = 6;
int y = x == 6 ? 5 : 9;
Nothing fancy, pretty straight forward.
Now, let's try to use this when assigning a Lambda to a Func type. Let me explain:
Func<Order, bool> predicate = id == null
? p => p.EmployeeID == null
: p => p.EmployeeID == id;
That's the same syntax, and should work? Right? For some reason that doesn't. The compiler gives this nice cryptic message:
Error 1 Type of conditional expression cannot be determined because there is no implicit conversion between 'lambda expression' and 'lambda expression'
I then went ahead and changed the syntax and this way it did work:
Func<Order, bool> predicate = id == null
? predicate = p => p.EmployeeID == null
: predicate = p => p.EmployeeID == id;
I'm just curious as to why it doesn't work the first way?
(Side note: I ended up not needing this code, as I found out that when comparing an int value against null, you just use object.Equals)
You can convert a lambda expression to a particular target delegate type, but in order to determine the type of the conditional expression, the compiler needs to know the type of each of the second and third operands. While they're both just "lambda expression" there's no conversion from one to the other, so the compiler can't do anything useful.
I wouldn't suggest using an assignment, however - a cast is more obvious:
Func<Order, bool> predicate = id == null
? (Func<Order, bool>) (p => p.EmployeeID == null)
: p => p.EmployeeID == id;
Note that you only need to provide it for one operand, so the compiler can perform the conversion from the other lambda expression.
The C# compiler cannot infer the type of the created lambda expression because it processes the ternary first and then the assignment. you could also do:
Func<Order, bool> predicate =
id == null ?
new Func<Order,bool>(p => p.EmployeeID == null) :
new Func<Order,bool>(p => p.EmployeeID == id);
but that just sucks,
you could also try
Func<Order, bool> predicate =
id == null ?
(Order p) => p.EmployeeID == null :
(Order p) => p.EmployeeID == id;
Let me have my own example since I had the same problem, too (with the hope that the example be helpful for others):
My Find method is generic method that gets Expression<Func<T, bool>> as predicate and gives List<T> as output.
I wanted to find countries, but I need all of them if language list was empty, and filtered list, if language list was filled.
First I used the Code as below:
var countries=
Find(languages.Any()
? (country => languages.Contains(country.Language))
: (country => true));
But exactly I get the error :there is no implicit conversion between lambda expression and lambda expression.
The problem was that, we have just two lambda expressions here, and nothing else, for example, what is country => true exactly?? We have to determine the type of at least one of lambda expressions. If just of one of the expressions be determined, then the error will be omitted. But for make the code more readable, I extracted both lambda expressions, and used the variable instead, as below:
Expression<Func<Country, bool>> getAllPredicate = country => true;
Expression<Func<Country, bool>> getCountriesByLanguagePredicate = country => languages.Contains(country.Language);
var countries= Find(languages.Any()
? getCountriesByLanguagePredicate
: getAllPredicate);
I emphasize that, if I just determined one of the expression's type, the error will be fixed.
Just an update - in C# 10, it IS now possible for the compiler to infer the 'natural type' of a lambda, provided that the input type(s) are provided, e.g.
var evenFilter = (int i) => i % 2 == 0; // evenFilter inferred as `Func<int, bool>`
This also means that 0 input Funcs and Actions can be inferred:
var zeroInputFunc = () => 44 % 2 == 0;
var myAction = () => {Console.WriteLine("Foo");};
However, this won't work:
var filter = i => i % 2 == 0; << Error: The delegate type could not be inferred
As a result, it is now possible to do what the OP originally wanted to do, provided that at least the input types are provided, e.g.
Func<int, bool> myPredicate = selectorFlag
? i => i % 2 == 0
: i => i % 2 == 1;
However, this still isn't permitted:
var myPredicate = selectorFlag
? (int i) => i % 2 == 0
: (int i) => i % 2 == 1;
Error : no implicit conversion between 'lambda expression' and 'lambda expression'