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

好久不见. 提交于 2019-11-26 05:31:07

问题


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)


回答1:


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.




回答2:


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;



回答3:


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.



来源:https://stackoverflow.com/questions/263151/how-can-i-assign-a-func-conditionally-between-lambdas-using-the-conditional-te

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!