簡體   English   中英

C#:隱式運算符和擴展方法

[英]C#: implicit operator and extension methods

我正在嘗試創建一個包含Expression<Func<T, bool>>PredicateBuilder<T>類,並提供一些方法來使用各種AndOr方法輕松構建表達式。 我認為如果我可以直接使用這個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)
    }
}

這兩個函數TrueFalse扮演你的PredicateBuilder(bool)構造函數的角色,你可能會有類似的原始比較等等,然后像And這樣的運算符會讓你把兩個表達式插在一起。

但是,您將失去使用運算符符號的功能,您可以將其與包裝器對象一起使用,而必須使用方法名稱。 我一直在玩同樣的方法,我總是回到過的地方是我希望能夠定義擴展操作符。 C#團隊顯然認為這些是3.0(以及擴展屬性),但它們的優先級較低,因為它們沒有參與Linq的整體目標。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM