问题我可以定义一个方法来接受 Func 或 Expression
我有一个过滤器方法
SelectItems
,它接受一个 Func<Thing, bool>
,其中 Thing
是集合中的单个项目,bool
返回值是该项目是否通过过滤器。
SelectItems
在代码库的多个地方使用。有些地方传递表达式 lambda,而其他地方传递语句 lambda。
如果集合中没有项目通过过滤器,它会抛出一个异常,并显示一条描述该集合的异常消息。因为这段代码在很多地方都被引用,所以我想在异常消息中添加过滤器本身的描述——比如
Item matching filter "(item) => item % 2 == 0" was not found. Items found: 1, 3, 5, 7
.
如果过滤器函数接受
Expression<Func<Thing, bool>>
,我可以使用 PrettyPrintCSharpCode
方法打印函数本身。可能还有其他方法可以从 Expression
中提取信息,但现在漂亮地打印代码就足够了。但是,如果传递了 Func
,消息将无法包含代码。这很好,可能是我上面链接的问题和我的问题之间最大的区别。
如果对该函数的所有调用都只传递表达式 lambda,我可以简单地将函数参数更改为
Expression
,它会隐式工作。我遇到的问题是许多调用都传递语句 lambda,所以这些调用中断了。
我想要的是能够传递表达式 lambda 或语句 lambda。
我尝试重载函数(一个重载接受 Func,另一个重载表达式),但编译器无法将表达式 lambdas 正确传递给接受
Expression
的函数,并将语句 lambdas 传递给除 之外的函数Func
.
我也试过可选参数(比如
SelectItems(Func<Thing, bool> func = null, Expression<Func<Thing, bool>> expr = null)
)但它有同样的问题。
如果我重载一个函数来接受一个
int
或一个double
,编译器会找出最合适的。我很困惑它不会为此这样做。
具体来说,代码
class ClassName
void SelectItems(Expression<Func<Thing, bool>> filterExpression) {}
void SelectItems(Func<Thing, bool> filterFunc) {}
生成此编译器错误
void ClassName.SelectItems(Func<Thing, bool> filterFunc) (+ 1 overload)
CS0121: The call is ambiguous between the following methods or properties:
'ClassName.SelectItems(Func<Thing, bool>)' and
'ClassName.SelectItems(Expression<Func<Thing, bool>>)'
Ambiguous invocation:
void SelectItems(System.Func<Thing, bool>) (in class ClassName)
void SelectItems(System.Linq.Expression<System.Func<Thing, bool>>) (in class ClassName)
match
有没有办法做到这一点?
您可以显式提供参数名称:
SelectItems(filterFunc: t => true); // uses Func overload
SelectItems(filterExpression: t => true); // uses Expression overload
虽然有点脆
另一种方式是显式指定类型:
SelectItems((Func<Thing, bool>)(t => true))
SelectItems((Expression<Func<Thing, bool>>)(t => true))
编译器也可以消除两者之间的歧义,问题是编译器从上下文中推断像
t => true
这样的 lambda 表达式的类型,并且 Func<T, bool>
和 Expression<Func<Thing, bool>>
在提供的情况下都是有效的,因此存在歧义。
来自规格:
表达式的结果被分类为以下之一:
- ...
- 匿名函数。具有此分类的表达式可以隐式转换为兼容的委托类型或表达式树类型。
- ...
和
匿名函数转换的评估取决于转换的目标类型:如果它是委托类型,则转换评估为引用匿名函数定义的方法的委托值。如果它是表达式树类型,则转换计算为将方法结构表示为对象结构的表达式树。