如何使用条件三元运算符在lambdas之间有条件地分配Func <>?

问题描述:

通常,使用条件运算符的时候,这里的语法:如何使用条件三元运算符在lambdas之间有条件地分配Func <>?

int x = 6; 
int y = x == 6 ? 5 : 9; 

没什么特别的,非常直截了当。

现在,让我们尝试在将Lambda分配给Func类型时使用它。让我来解释:

Func<Order, bool> predicate = id == null 
    ? p => p.EmployeeID == null 
    : p => p.EmployeeID == id; 

这是相同的语法和应该工作?对?由于某些原因,不。编译器提供了这个漂亮的神秘消息:

错误不能确定1型条件表达式,因为有“lambda表达式”和“lambda表达式”

然后我继续和之间的隐式转换改变了语法和这种方式工作:

Func<Order, bool> predicate = id == null 
    ? predicate = p => p.EmployeeID == null 
    : predicate = p => p.EmployeeID == id; 

我只是好奇,为什么它不工作的第一种方式?

(附注:我结束了不需要的代码,因为我发现,对比较空的int值时,你只需要使用的Object.Equals)

您可以lambda表达式转换为特定目标委托类型,但为了确定条件表达式的类型,编译器需要知道每个第二个和第三个操作数的类型。虽然它们都只是“lambda表达式”,但它们之间没有转换,所以编译器不能做任何有用的事情。

使用赋值我不会建议,但是 - 铸造更加明显:

Func<Order, bool> predicate = id == null 
    ? (Func<Order, bool>) (p => p.EmployeeID == null) 
    : p => p.EmployeeID == id; 

请注意,您只需要为一个操作数提供,所以编译器可以从其他执行转换lambda表达式。

+0

我想知道,如果编译器可以推断出这个:`Func predicate = p => p.EmployeeID == id`,怎么会有这个麻烦推断这个:`Func predicate = id == null ? (函数)(p => p.EmployeeID == null) :p => p.EmployeeID == id;`?我的意思是它知道第二个和第三个操作数通过`predicate`声明需要的类型。 – GDS 2016-10-17 09:48:57

+0

@GDS:有一个从lambda表达式到委托类型的隐式转换,这就是第一个版本工作的原因。但是`predicate`的声明不会影响条件表达式的类型推断。语言规范基本上说,条件表达式的类型只能通过操作数来推断。 – 2016-10-17 10:07:11

C#编译器无法推断创建的lambda表达式的类型,因为它先处理三元组,然后再处理分配。你也可以这样做:

Func<Order, bool> predicate = 
    id == null ? 
     new Func<Order,bool>(p => p.EmployeeID == null) : 
     new Func<Order,bool>(p => p.EmployeeID == id); 

但只是很烂, 你也可以尝试

Func<Order, bool> predicate = 
    id == null ? 
     (Order p) => p.EmployeeID == null : 
     (Order p) => p.EmployeeID == id; 

让我有我自己的例子,因为我有同样的问题,太(与希望的例子对其他人有帮助):

我的Find方法是获取Expression<Func<T, bool>>作为谓词并给出List<T>作为输出的一般方法。
我想查找国家,但是如果语言列表为空,并且过滤列表(如果语言列表已填写),我需要所有国家/地区。 首先,我使用的代码如下:

var countries= 
Find(languages.Any() 
    ? (country => languages.Contains(country.Language)) 
    : (country => true)); 

但正是我得到的错误:there is no implicit conversion between lambda expression and lambda expression.

的问题是,我们只有两个拉姆达在这里表达,而不是其他,例如,是什么country => true究竟是什么?我们必须确定至少一个lambda表达式的类型。如果只有一个表达式被确定,那么错误将被省略。但为使代码的可读性,我提取两个lambda表达式,和所使用的变量,而不是,如下:

Expression<Func<Country, bool>> getAllPredicate = country => true; 
    Expression<Func<Country, bool>> getCountriesByLanguagePredicate = country => languages.Contains(country.Language); 

    var countries= Find(languages.Any() 
         ? getCountriesByLanguagePredicate 
         : getAllPredicate); 

我强调的是,如果我刚确定的表达式的类型中的一个,该错误将被固定。