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

发布于 2024-07-08 12:58:02 字数 765 浏览 11 评论 0 原文

一般来说,使用条件运算符时,语法如下:

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)

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

淡墨 2024-07-15 12:58:02

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

不过,我不建议使用赋值 - 强制转换更为明显:

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

请注意,您只需为一个操作数提供它,这样编译器就可以执行来自其他 lambda 表达式的转换。

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.

清音悠歌 2024-07-15 12:58:02

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;

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;
梦境 2024-07-15 12:58:02

让我有自己的例子,因为我也遇到了同样的问题(希望该示例对其他人有帮助):

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

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

但我确实得到了错误:lambda 表达式和 lambda 表达式之间没有隐式转换。

问题是,我们这里只有两个 lambda 表达式,没有其他任何东西,例如,什么是 country => 完全正确? 我们必须确定至少一个 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);

我强调,如果我只确定其中一种表达式的类型,则错误将被修复。

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.

旧话新听 2024-07-15 12:58:02

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

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

这也意味着 0 输入可以推断出功能和动作:

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 表达式”之间没有隐式转换

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'

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文