2009-03-26 14 views
11

Expression<Func<T, bool>>をラップするPredicateBuilder<T>クラスを作成しようとしていて、様々なAndOrメソッドを持つ式を簡単に構築する方法をいくつか提供しています。このPredicateBuilder<T>Expression<Func<T, bool>>と直接使うことができれば涼しいと思っていましたが、これはimplicit operatorメソッドのものを使って行うことができます。C#:暗黙の演算子と拡張メソッド

クラスのバージョンのようになりますダウン剥奪:私は、私の頭では

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

:単なるテストとして、私は静的クラスで、この拡張子の方法を持っている、そして、

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

をこれらを行うことができるはずです:

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の仕組みについて何か誤解しましたか?

+3

クリーンアップありがとう!私は延長の代わりにエクステンションを書いています...なぜか分かりません!私はちょっと...止められない... = S – Svish

答えて

11

これは拡張メソッドに固有のものではありません。 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? 
+0

私は両方とも言います。ナー、それはポイント、heheだと思います。 – Svish

+3

"Foo()があいまいです:B.Foo()またはC.Foo()"と思われます。 –

+1

@Anton:可能ですが、言語が複雑になり、副作用が隠される可能性があります。そして、結局のところ、暗黙の演算子をクラスに定義するときに、作業コードが突然途切れると、どう思いますか?明示的な型宣言をどこでも強制するのは簡単です。 –

2

いいえ、そうではありませんが、C#コンパイラの型減算はコードを理解するのに十分強力ではなく、特に暗黙の演算子は見ません。 Expression<Func<T,bool>>に固執する必要があります。OrAndなどの拡張メソッドを直接式に置くのはなぜですか?

+0

aha、ok、それは技術的にはうまくいくはずです。暗黙の演算子型のものに拡張メソッドを探すのではないのですか? – Svish

+0

私は "理想的には"うまくいくと言うでしょう:)ちょうど、それは見た目を知るのに十分強力ではありません。 –

+0

既にこれらの拡張方法があります。しかし、私はこのような式を構築するときに作業を少し楽にしようとしています。とにかく私が成功するかどうかわからない:p – Svish

0

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などのオペレータと思います2つの式を一緒につなげることができます。

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

+0

「拡張式を '式>' 'に直接置きますか?私はすでに何をしていますか?あるいは、 'PredicateBuilder 'ではなく、 'Expression >'でそれを使うことを意味しますか? (それはちょうど通常の使用であり、もちろん動作します) – Svish

+0

説明を参照してください。 –

+0

私はそれを得ることはありません... – Svish

関連する問題