C#:隐式运算符和扩展方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/685156/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 13:23:41  来源:igfitidea点击:

C#: implicit operator and extension methods

c#operator-overloadingextension-methods

提问by Svish

I am trying to create a PredicateBuilder<T>class which wraps an Expression<Func<T, bool>>and provides some methods to easily build up an expression with various Andand Ormethods. I thought it would be cool if I could use this PredicateBuilder<T>as an Expression<Func<T, bool>>directly, and thought this could be done by having an implicit operatormethod thing.

我想创建一个PredicateBuilder<T>它包装的类Expression<Func<T, bool>>,并提供一些方法来轻松地建立了各种的表达AndOr方法。我认为这将是冷静,如果我可以用这PredicateBuilder<T>一个是Expression<Func<T, bool>>直接,认为这可以由具有进行implicit operator方法的事情。

Stripped down version of the class looks like this:

该类的精简版本如下所示:

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;
    }
}

Then, just as a test, I have this extention method in a static class:

然后,作为测试,我在静态类中有这个扩展方法:

public static void PrintExpression<T>(this Expression<Func<T, bool>> expression)
{
    Console.WriteLine(expression);
}

In my head, I should then be able to do these:

在我的脑海中,我应该能够做到这些:

var p = new PredicateBuilder<int>(true);

p.PrintExpression();
PredicateExtensions.PrintExpression(p);

However none of them work. For the first one, the extension method is not found. And for the second, it says that

然而,它们都不起作用。对于第一个,没有找到扩展方法。第二,它说

The type arguments for method 'ExtravagantExpressions.PredicateHelper.PrintExpression(System.Linq.Expressions.Expression>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

无法从用法推断方法“ExtravagantExpressions.PredicateHelper.PrintExpression(System.Linq.Expressions.Expression>)”的类型参数。尝试明确指定类型参数。

So I tried the following, which worked:

所以我尝试了以下方法,效果很好:

PredicateExtensions.PrintExpression<int>(p);

Also, this works, of course:

此外,这当然有效:

((Expression<Func<int, bool>>) p).PrintExpression();

But yeah... why don't the others work? Have I misunderstood something about how this implicit operatorthing works?

但是是的......为什么其他人不工作?我是否误解了这implicit operator件事的工作原理?

采纳答案by Mehrdad Afshari

This is not specific to extension methods. C# won't implicitly cast an object to another type unless there is a clue about the target type. Assume the following:

这不是特定于扩展方法的。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() { ... }
}

Which method would you expect to be called in the following statement?

您希望在以下语句中调用哪个方法?

new A().Foo(); // B.Foo? C.Foo? 

回答by Anton Tykhyy

No, you haven't, but C# compiler's type deduction isn't powerful enough to understand your code, and in particular, it doesn't look at implicit operators. You'll have to stick with Expression<Func<T,bool>>— why not have extension methods like Or, Anddirectly on expressions?

不,您没有,但是 C# 编译器的类型推导功能不足以理解您的代码,特别是,它不考虑隐式运算符。你必须坚持Expression<Func<T,bool>>——为什么不直接在表达式上使用像Or,这样的扩展方法And

回答by Daniel Earwicker

As Anton says, if you put the extension methods directly on Expression<Func<...>>it would probably work.

正如安东所说,如果你直接将扩展方法放在Expression<Func<...>>它上面可能会起作用。

More explanation... nothing particularly clever, but the idea would be that you don't have a PredicateBuilderclass that you create instances of. Instead you just have purely static building blocks:

更多解释......没有什么特别聪明的,但这个想法是你没有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)
    }
}

Those two functions Trueand Falseplay the role of your PredicateBuilder(bool)constructor, and you'd presumably have similar ones for primitive comparisons and so on, and then operators like Andwould let you plug two expressions together.

这两个功能True,并False发挥你的作用PredicateBuilder(bool)构造函数,你大概有基本数据类型比较相似的人等,然后像运营商And将让你插上两个表达式在一起。

However, then you lose the ability to use operator symbols, which you could have used with your wrapper object, and instead you have to use method names. I've been playing around with the same kind of approaches, and the thing I always come back to is that I want to be able to define extension operators. The C# team apparently considered these for 3.0 (along with extension properties) but they were lower priority because they didn't play a part in the overall aims of Linq.

但是,您将失去使用运算符符号的能力,而您可以将其与包装器对象一起使用,而必须使用方法名称。我一直在尝试使用相同的方法,而我总是想回想一下,我希望能够定义扩展运算符。C# 团队显然在 3.0 中考虑了这些(以及扩展属性),但它们的优先级较低,因为它们在 Linq 的总体目标中没有发挥作用。