[英]C#: implicit operator and extension methods
我正在尝试创建一个包含Expression<Func<T, bool>>
的PredicateBuilder<T>
类,并提供一些方法来使用各种And
和Or
方法轻松构建表达式。 我认为如果我可以直接使用这个PredicateBuilder<T>
作为Expression<Func<T, bool>>
会很酷,并且认为这可以通过implicit operator
方法来完成。
这个类的精简版看起来像这样:
class PredicateBuilder<T>
{
public Expression<Func<T, bool>> Predicate { get; protected set; }
public PredicateBuilder(bool initialPredicate)
{
Predicate = initialPredicate
? (Expression<Func<T, bool>>) (x => true)
: x => false;
}
public static implicit operator Expression<Func<T, bool>>(
PredicateBuilder<T> expressionBuilder)
{
return expressionBuilder.Predicate;
}
}
然后,就像测试一样,我在静态类中有这个扩展方法:
public static void PrintExpression<T>(this Expression<Func<T, bool>> expression)
{
Console.WriteLine(expression);
}
在我的脑海中,我应该能够做到这些:
var p = new PredicateBuilder<int>(true);
p.PrintExpression();
PredicateExtensions.PrintExpression(p);
但是它们都不起作用。 对于第一个,找不到扩展方法。 而对于第二个,它说
无法从用法中推断出方法'ExtravagantExpressions.PredicateHelper.PrintExpression(System.Linq.Expressions.Expression>)'的类型参数。 尝试显式指定类型参数。
所以我尝试了以下工作:
PredicateExtensions.PrintExpression<int>(p);
此外,这当然有效:
((Expression<Func<int, bool>>) p).PrintExpression();
但是,为什么其他人不工作呢? 我是否误解了这个implicit operator
的工作原理?
这不是扩展方法特有的。 除非有关于目标类型的线索,否则C#不会隐式地将对象强制转换为其他类型。 假设如下:
class A {
public static implicit operator B(A obj) { ... }
public static implicit operator C(A obj) { ... }
}
class B {
public void Foo() { ... }
}
class C {
public void Foo() { ... }
}
您希望在以下语句中调用哪种方法?
new A().Foo(); // B.Foo? C.Foo?
不,你没有,但C#编译器的类型推导不够强大,无法理解你的代码,特别是它不会看隐式运算符。 你必须坚持使用Expression<Func<T,bool>>
- 为什么没有像Or
这样的扩展方法, And
直接在表达式上?
正如Anton所说,如果将扩展方法直接放在Expression<Func<...>>
它可能会起作用。
更多的解释......没有什么特别聪明,但想法是你没有一个你创建实例的PredicateBuilder
类。 相反,你只有纯粹的静态构建块:
public static class Predicates
{
public static Expression<Func<T, bool>> True<T>()
{
return x => true;
}
public static Expression<Func<T, bool>> False<T>()
{
return x => false;
}
public static Expression<Func<T, bool>> And<T>(
this Expression<Func<T, bool>> left,
Expression<Func<T, bool>> right)
{
return ... // returns equivalent of (left && right)
}
}
这两个函数True
和False
扮演你的PredicateBuilder(bool)
构造函数的角色,你可能会有类似的原始比较等等,然后像And
这样的运算符会让你把两个表达式插在一起。
但是,您将失去使用运算符符号的功能,您可以将其与包装器对象一起使用,而必须使用方法名称。 我一直在玩同样的方法,我总是回到过的地方是我希望能够定义扩展操作符。 C#团队显然认为这些是3.0(以及扩展属性),但它们的优先级较低,因为它们没有参与Linq的整体目标。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.