passing in nullable Expression<Func<T, TResult>>? as method parameter? - c#

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.

Related

Func<int, int> from conditional expression [duplicate]

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'

Meaning of Func<object, bool>(p => true)

I saw this line of code:
var myFilter= val1 ? (Func<Person, bool>)(person=> true) : (person=> person.IsValid);
What does this part means?:
(Func<Person, bool>)(person=> true)
Then, the myFilter variable is being used to filter some data from a table...
return ctx.Persons.Where(myFilter).ToList();
What happens when val1 is true and the first part of the conditional (Func<Person, bool>)(person=> true) is selected?
The Where method takes a parameter of type Func<T, bool> - this is essentially a function that takes a T (in this case, Person) as a parameter, and returns a bool. The Where method evaluates this function for each object in the source list and filters to only those that result in true.
The delegate person => true defines a method that takes a Person as a parameter and always returns true, regardless of the Person object. When used in a Where clause, this will never filter out anything and returns the original set of items. (The cast to Func<T, bool> is required because of the use of var - the compiler can't determine the type of an anonymous delegate without a hint.)
So this code:
var myFilter = val1 ? (Func<Person, bool>)(person => true) : (person => person.IsValid);
return ctx.Persons.Where(myFilter).ToList();
does the same thing as this:
if (val1)
{
return ctx.Persons.ToList();
}
else
{
return ctx.Persons.Where(person => person.IsValid).ToList();
}
In such case the expression passed to Where returns true always - for any Person passed to it.
For the conditional operator to compile, the two expressions need to have the same type. Lambdas have unique types, so two lambdas don't have the same type. By casting (at least) one of these lambdas to a Func<Person, bool>, the common type of the two expression can be determined to be Func<Person, bool> by implicit conversion of the other lambda to the Func type.
So myFilter is now either the function that always returns true, or if val1 is false, actually does some filtering when used as a Where clause.

Why are these two LINQ queries different? When they seem to be the same

I would like know why these two LINQ queries are different, or why one works and the other does not? Obviously the compiler says they are different, but I can't seem to find out why?
I want the first query to work, but no matter what I do It won't work.
The below LINQ query gives me an error of,
Cannot implicitly convert type 'int?' to
'System.Collections.Generic.IEnumerable'
public static IEnumerable<int?> GetTenantFacilityCosts(int? code, DateTime date, int number)
{
return DataContext.Facility_Cost_TBLs.
Where(p => p.Tenant_Code == code &&
p.Code_Date == number &&
p.Date_Year == date.Year &&
p.Date_Month == date.Month).
FirstOrDefault().Tenant_Portion;
}
But this query below gets the int value that I am trying to get and does not throw an error.
int? facilityCost =
DataContext.Facility_Cost_TBLs.
Where(p => p.Tenant_Code == selectedTenant.Tenant_Code &&
p.Code_Date == 10 &&
p.Date_Year == date.Year &&
p.Date_Month == date.Month).
FirstOrDefault().Tenant_Portion;
Why are these two queries differnt and how would I get the first one to work correctly?
As you can see from the one that works, the result of your query is an int?. When you've turned that to a function the return type of your function is IEnumerable<int?>.
You function should be
public static int? GetTenantFacilityCosts(int? code, DateTime date, int number)
{
...
}
The Linq query returns a nullable int i.e. int?, the reason it works for the second is because it is assigning the value to a int?.
The second one is returning a int? on a method that is trying to return: IEnumerable<int?>. If you want to return an enumerable of the results you need to remove the FirstOrDefault from the query. And judging by the method name, i.e. the plural Costs, this is what you want.
However if you only want one result change the method signature to:
public static int? GetTenantFacilityCosts(int? code, DateTime date, int number)

Cannot convert from 'System.Collections.Generic.IEnumerable<int>' to 'System.Collections.Generic.IEnumerable<int?>'

class first
{
private int? firstID;
}
class second
{
private int secondID;
private int secondField;
}
public override Expression<Func<first, bool>> FirstFilter()
{
Contex db = new Contex();
List<second> list = (from p in db.second select p).ToList();
return b => list.Select(p => p.secondID).Contains(b.firstID);
}
and I have error:
cannot convert from 'System.Collections.Generic.IEnumerable' to 'System.Collections.Generic.IEnumerable'
I have tried many different ways, but I just don't know how can I fix it.
Use this:
list.Select(p => p.secondID).Cast<int?>().Contains(b.firstID);
You are getting the problem, because list.Select(p => p.secondID) will be an IEnumerable<int?, but because firstID is int (non-nullable), overload resolution cannot determine a valid overload of Contains to call. You cannot implicitly convert from IEnumerable<int?> to IEnumerable<int>. The Cast extension method works by casting each element to int.
As mentioned in another answer, you could also simply pass in a non-nullable int into Contains:
list.Select(p => p.secondID).Contains(b.firstID ?? 0);
But, do be aware that this might not be want. If the first list contains 0, and firstID is null, the result will be true, because you pass in 0 when the value is null.The Cast version of the expression returns false when firstID is null.
Try providing a default value for firstID if it is null:
return b => list.Select(p => p.secondID).Contains(b.firstID ?? 0);

How can I assign a Func<> conditionally between lambdas using the conditional ternary operator?

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'

Categories

Resources