14

PredicateBuilder<T>をラップし、さまざまなメソッドを使用して式を簡単に作成するためのいくつかのメソッドを提供するクラスをExpression<Func<T, bool>>作成しようとしています。これを直接使ってみたらかっこいいなぁと思い、メソッドを持っていればできると思いました。AndOrPredicateBuilder<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

4

3 に答える 3

15

これは、拡張メソッドに固有のものではありません。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? 
于 2009-03-26T10:48:20.400 に答える
2

いいえ、そうではありませんが、C#コンパイラの型推論は、コードを理解するのに十分なほど強力ではありません。特に、暗黙の演算子を調べません。固執する必要があります—式に直接、Expression<Func<T,bool>>のような拡張メソッドを使用してみませんか?OrAnd

于 2009-03-26T10:16:27.870 に答える
0

アントンが言うように、拡張メソッドを直接配置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)
    }
}

これらの 2 つの関数TrueとコンストラクターFalseの役割を果たしPredicateBuilder(bool)ます。おそらく、プリミティブな比較などに同様の関数があり、演算子 likeAndを使用して 2 つの式を結合できます。

ただし、ラッパー オブジェクトで使用できた演算子記号を使用できなくなり、代わりにメソッド名を使用する必要があります。私は同じ種類のアプローチをいじっていましたが、いつも戻ってくるのは、拡張演算子を定義できるようにしたいということです。C# チームはこれらを (拡張プロパティと共に) 3.0 向けに検討したようですが、Linq の全体的な目的には関与していないため、優先度は低くなりました。

于 2009-03-26T10:31:30.707 に答える