C# 编译器错误:无法转换 lambda 表达式

Posted

技术标签:

【中文标题】C# 编译器错误:无法转换 lambda 表达式【英文标题】:C# compiler error: Cannot convert lambda expression 【发布时间】:2011-07-15 13:08:15 【问题描述】:

我正在尝试使用 Lambda 表达式和反射来获取成员分层名称(而不是使用文本常量),以在我的控件绑定信息无效时强制执行编译时错误。

这是在 ASP.NET MVC 项目中,但它不是特定于 MVC 的问题 AFAIK。编辑:具体来说,我希望以下评估为真:

string fullname = GetExpressionText(model => model.Locations.PreferredAreas);
"Locations.PreferredAreas" == fullname;

我得到一个编译错误:

错误 4:无法将 lambda 表达式转换为类型 'System.Linq.Expressions.LambdaExpression' 因为它不是委托类型。

为什么参数在下面的第二种情况下起作用,而在第一种情况下不起作用?

// This doesn't compile:
string tb1 = System.Web.Mvc.ExpressionHelper.
    GetExpressionText(model => model.Locations.PreferredAreas);

// But this does:
MvchtmlString tb2 =
    Html.TextBoxFor(model => model.Locations.PreferredAreas);

这是来自 ASP.NET MVC Codeplex 项目的相关代码。在我看来,它将相同的参数传递给相同的方法:

// MVC extension method
public static MvcHtmlString TextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes) 
    ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
    return TextBoxHelper(
        htmlHelper,
        metadata,
        metadata.Model,
        ExpressionHelper.GetExpressionText(expression),
        htmlAttributes);


// MVC utility method
public static string GetExpressionText(LambdaExpression expression) 
    // Split apart the expression string for property/field accessors to create its name
    // etc...

【问题讨论】:

你忘了包括你的问题最相关的部分——GetExpressionText 源代码:) 没关系,它是一个 MVC 助手。看我的回答。 这真的相关吗?基于 Eric Lippert 的回答(他回答的内容,而不仅仅是他能够回答的事实)GetExpressionText 背后的来源不相关,对吧? 你还记得你最终做了什么吗?那个代表埃里克在说什么? 查看下面的另一个答案以获得代码示例,Lum。 【参考方案1】:

错误信息是正确的。可以将 lambda 转换为兼容的委托类型 D 或表达式兼容的委托类型 Expression&lt;D&gt;Expression&lt;Func&lt;TM, TP&gt;&gt; 就是其中之一。 “LambdaExpression”不是那些。因此,您在尝试将 lambda 转换为 LambdaExpression,而不是实际的表达式树类型时遇到错误。那里一定有一个代表

【讨论】:

谢谢你,埃里克,我相信你是对的。我正在努力理解它:) 所以你说 (lambda to Expression to LambaExpression) 是有效的并且正在发生什么,但是 (lambda to LambdaExpression) 不是? @shannon:正确。 LambdaExpression 是 Expression基类lambda 需要知道委托类型是什么。你所说的只是“这个 lambda 表达式应该被视为一个 lambda 表达式”这并没有给编译器任何继续。你需要说“这个 lambda 表达式应该被视为一个表达式树,用于接受一个 int 并返回一个字符串的表达式”或其他什么。那里需要有一个委托类型。 是的,这就是我感到困惑的地方,因为 TM 和 TP 都是推断出来的,所以编译器已经知道 lamba 是一个接受 TM 并返回 TP 的表达式。不过,我相信我会解决的:) @shannon:从 TM 推断出什么? (您发布的调用站点和扩展方法似乎不匹配。)当您解决问题时,您会发现 TM 不是从 lambda 推断出来的; lambda 中没有足够的信息来确定“模型”的类型必须是什么;该信息必须来自 somewhere 并且在 LambdaExpression 情况下,您不会将该信息提供给任何地方的编译器。【参考方案2】:

在尝试修复 lambda 表达式之前,请确保已添加以下引用:

System.Linq; System.Linq.Expressions;

缺少这些引用也可能导致相同的错误(“无法将 lambda 表达式转换为类型 'System.Linq.Expressions.Lambda 表达式',因为它不是委托类型”)。

希望这会有所帮助...

【讨论】:

【参考方案3】:

我认为你应该尝试使用这样的辅助方法:

public static string GetExpressionText<M, P>(this M model, Expression<Func<M, P>> ex)

    return GetExpressionText(ex);

【讨论】:

这似乎可行,但M的实例不是必需的,所以这实际上不属于扩展方法,对吧? 没错,您可以将此帮助程序声明为GetExpressionText&lt;M, P&gt;(Expression&lt;Func&lt;M, P&gt;&gt; ex),但在这种情况下,您必须明确指定类型参数。扩展方法语法更简洁,虽然它需要声明一个“未使用”参数。 对不起,我无法在两个地方给出答案 - Eric 修复了我的大脑,你给了我我需要的代码......这是一个折腾,但我认为 Eric 回答了我的问题并在此过程中尝试(几乎成功)教一个人钓鱼。

以上是关于C# 编译器错误:无法转换 lambda 表达式的主要内容,如果未能解决你的问题,请参考以下文章

C# 10 Lambda 语法的改进

错误:无法将 lambda 表达式转换为类型“bool”,因为它不是 Kendo Chart 中的委托类型

实体框架 - 无法将 lambda 表达式转换为类型“字符串”,因为它不是委托类型

如何将 C# lambda 表达式转换为委托?

C#进阶 | 全面解析Lambda表达式

转载 C#匿名函数 委托和Lambda表达式