52

通常,使用条件运算符时,语法如下:

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 值与 null 进行比较时,您只需使用 object.Equals)

4

4 回答 4

54

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

但是,我不建议使用分配 - 演员表更明显:

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

请注意,您只需为一个操作数提供它,因此编译器可以从另一个 lambda 表达式执行转换。

于 2008-11-04T19:45:18.927 回答
5

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;
于 2008-11-04T19:46:58.877 回答
1

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

我的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.

问题是,我们这里只有两个 lambda 表达式,没有别的,例如,究竟是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);

我强调的是,如果我只是确定了表达式的一种类型,那么错误将得到修复。

于 2018-01-16T06:10:08.850 回答
1

只是一个更新 - 在 C# 10 中,编译器现在可以推断lambda 的“自然类型”,前提是提供了输入类型,例如

var evenFilter = (int i) => i % 2 == 0; // evenFilter inferred as `Func<int, bool>`

这也意味着可以推断出 0 个输入 Funcs 和 Actions:

var zeroInputFunc = () => 44 % 2 == 0;
var myAction = () => {Console.WriteLine("Foo");};

但是,这不起作用:

var filter = i => i % 2 == 0; << Error: The delegate type could not be inferred

因此,现在可以做 OP 最初想做的事情,前提是至少提供了输入类型,例如

Func<int, bool> myPredicate = selectorFlag
    ? i => i % 2 == 0
    : i => i % 2 == 1;

但是,这仍然是不允许的:

var myPredicate = selectorFlag
    ? (int i) => i % 2 == 0
    : (int i) => i % 2 == 1;

错误:“lambda 表达式”和“lambda 表达式”之间没有隐式转换

于 2021-12-02T12:29:09.157 回答