表达式/函数重载的编译器错误

Posted

技术标签:

【中文标题】表达式/函数重载的编译器错误【英文标题】:Compiler Error for Expression/Func overloads 【发布时间】:2015-03-10 05:10:41 【问题描述】:

截图说明了这一点。 如屏幕截图所示,我有重载。当使用字符串作为第二个参数时,编译器应该确定第一个参数只能是 Func 而不是表达式。 但是编译器会抛出一个错误,说“不能将带有语句体的 lamda 表达式转换为表达式树”。

为什么编译器不能找出正确的重载?

显式转换没有帮助。有效的是当我创建一个 Func 类型的局部变量然后使用它时。

使用的框架是 FakeItEasy 1.24.0

编辑

这是显示行为的代码:

public static void Main(string[] args)
    
        //compiler error
        A.CallTo(() => Main(A<string[]>.That.Matches(strings =>
                                                     
                                                         return true;
                                                     , "description")));

        //compiles
        Func<string[], bool> predicate = strings =>
                         
                             return true;
                         ;
        A.CallTo(() => Main(A<string[]>.That.Matches(predicate, "description")));

        Console.ReadLine();
    

【问题讨论】:

你能把代码贴出来而不是截图吗? 您不要在仅表达式的 lambda 正文中使用 return...string =&gt; true 就足够了。 @leppie:正确,但这不是重点。正如您在屏幕截图中看到的那样,编译器应该使用带有 Func 的重载,因此方法体应该没问题。编译器会给出错误。问题是为什么。 @leppie:第二个参数是一个字符串,因此表达式的重载应该不在图片中,因为这个重载只有一个参数。 @leppie:好点,但没有默认值。 【参考方案1】:

问题不在于对Matches 的调用。它在对CallTo 的调用中,它需要Expression&lt;Action&gt;

显然Expression 不仅不能是带有语句体的 lambda 表达式,它也不能包含带有语句体的 lambda 表达式。

(我不确定您的“将 lambda 放入局部变量”解决方案是否会工作,或者它是否只是欺骗编译器并在运行时失败。)

这是我整理的测试:

static void Overloaded(Action a, string param)  
static void Overloaded(Expression<Action> e)  

static void CallToAction(Action a)  
static void CallToExprAc(Expression<Action> a)  

static void Main(string[] args)

    // Works
    CallToAction(() => Overloaded(() =>  int i = 5; , "hi"));

    // Doesn't work - using the Expression overload
    CallToAction(() => Overloaded(() =>  int i = 5; ));

    // Doesn't work - wrapped in an outer Expression
    CallToExprAc(() => Overloaded(() =>  int i = 5; , "hi"));

您的“将表达式主体的 lambda 放入本地”是否有效取决于 FakeItEasy 的实现方式。我怀疑它会在这里工作,但在例如类似的东西。 LINQ-to-SQL 不会——它只会在运行时而不是在编译时失败。

我不确定这是编译器错误、规范错误还是理想行为。在 C# 规范的第 6.5 节中,我们有

某些 lambda 表达式无法转换为表达式树类型:即使转换存在,它在编译时也会失败。如果 lambda 表达式是这种情况:

• 有块体

• 包含简单或复合赋值运算符

• 包含动态绑定的表达式

• 是异步的

其中没有说“包含无法转换为表达式树类型的 lambda 表达式”。

【讨论】:

啊..好点!是的,当你创建一个局部变量时,它也可以在运行时工作。谢谢! @MarChr 很高兴听到它,而且是个好地方——当然是一个有趣的问题。 是的,但现在也有意义。谢谢! 因为我认为这是一个编译器错误,所以我提出了它here。

以上是关于表达式/函数重载的编译器错误的主要内容,如果未能解决你的问题,请参考以下文章

为什么要用函数重载

C++ bool 表达式作为函数参数调用错误的重载

C++ 编译器错误:对重载函数的模糊调用

函数重载的使用

VC++2010 中的编译器错误(2008 年干净!),“对重载函数的模糊调用”

小于运算符不能作为成员函数重载