2011-01-13 8 views
3

私は式ツリーを解析する必要があるプロジェクトに取り組んでいます。私は大部分の作業を行いましたが、少し問題がありました。式ツリー解析、変数は定数として終了する

私は式の木の上にStackOverflowの上の他の質問を見てきたが、私の質問への答えを見つけるように見えるので、ここでは行くことができません。

私の問題は、定数と変数の違い(または不足)です。私は例から始めましょう:

user => user.Email == email 

これは明らかに一定ではなく変数ではないが、これはどこかで式ツリー内のConstantExpressionされて終わります。あなたは式自体を見てみた場合、それは少し奇妙に見える:

Expression = {value(stORM.Web.Security.User+<>c__DisplayClassa)} 

我々は別の例取る場合:ここで私はENUM(TaskStatus)を使用してい

task => task.Status != TaskStatus.Done && t.Status != TaskStatus.Failed 

を。ツリー解析で、私は両方のケースでConstantExpressionで終わるように見える、と私は本当にそれらを区別できるようにする必要があること

だから私の問題があります。これらは単なる例なので、私が求めているのは、これらの2つのタイプの式を互いに伝える一般的な方法です。したがって、私は解析で2つの異なる方法で処理できます。

EDIT:大丈夫、例がわからない場合がありますので、もう一度お試しください。最初の例:

ユーザーユーザー= db.Search <ユーザー>(U => u.Email ==メール)

私は指定されたメールアドレスでユーザーを探しています。私はこれをストアドプロシージャに解析していますが、それは私が推測する点のほかにあります。

第二の例:

のIList <タスク>タスク= db.Search(!!T => t.Status = TaskStatus.Done & & t.Status = TaskStatus.Failed);

ここでは、DoneとFailedとは異なるステータスのすべてのタスクを検索しようとしています。 これもまた、ストアドプロシージャに解析されています。最初の例では、私のコードは、ストアドプロシージャが電子メール変数の値である入力パラメータを必要としているかどうかを判断する必要があります。 2番目の例では入力パラメータは必要ありません。DoneとFailedと異なるステータスのタスクを選択するためにSQLを作成するだけです。

ありがとうございました

答えて

2

名前は少し残念ですが、実際には定数ではありません。

単に、式の外側の値を参照します。

2

Aは、可変(email有する第一の場合)は、典型的には "変数" のFieldInfoからMemberExpressionで、キャプチャクラスのインスタンスを表すConstantExpressionで捕捉 - あなたが持っていたかのように:

private class CaptureClass { 
    public string email; 
} 
... 
var obj = new CaptureClass(); 
obj.email = "[email protected]"; 

ここで、objは式の中の定数です。

so:フィールドのMemberExpressionConstantExpressionになると、(おそらく)がキャプチャされた変数になります。またリテラル定数は、一般的にだけConstantExpressionなります

...キャプチャクラスにCompilerGeneratedAttributeをチェックすることができ;

() => "abc".Length 

が、ここで.Lengthおそらく文字列プロパティ(ないフィールド)で、:のようなものは、あなたは可能性がない限り、実際には、あなたが定数のメンバーを使用したシナリオを考えるのは難しいだろう[CompilerGenerated]がありません。

+0

私の質問では十分明確ではないかもしれませんが、電子メールは実際にはユーザーオブジェクトのプロパティです。 –

+0

@SteenT - 表現ツリーはどのように見えますか? 'email'は暗黙のうちに' this.email'であるので、静かに 'this'をキャプチャするのと同じことかもしれません。だから、私は*メンバーが "期待している"かもしれません(私が何を意味するか分かります) –

+0

@SteenT - ああ、私の答えでは私は右の 'email'について話していました手の側。上記のコメントは、左側の 'user.Email'を説明する必要があります。 –

3

したがって、式の観点から、値は定数です。式では変更できません。

潜在的に開いている閉包 - すなわち、値は式の実行間で変更できますが、その間は変更できません。だから、それは "定数"です。これは関数型プログラミングと機能しないプログラミングの世界のパラダイムの違いです。

は、用語aが包み込むと、スタック上の変数にアクセスする匿名クラスへのメンバーのアクセスである

 int a =2; 
     Expression<Func<int, int>> h = x=> x+ a; 
     Expression<Func<int, int>> j = x => x +2; 
     a = 1; 

考えてみましょう。最初のノードはMemberAccessノードで、その下には式が定数です。

((SimpleBinaryExpression)(h.Body)).Right 
{value(WindowsFormsApplication6.Form1+<>c__DisplayClass0).a} 
    CanReduce: false 
    DebugView: ".Constant<WindowsFormsApplication6.Form1+<>c__DisplayClass0>(WindowsFormsApplication6.Form1+<>c__DisplayClass0).a" 
    Expression: {value(WindowsFormsApplication6.Form1+<>c__DisplayClass0)} 
    Member: {Int32 a} 
    NodeType: MemberAccess 
    Type: {Name = "Int32" FullName = "System.Int32"} 

そして、その下に定数::上記のコードの場合

((MemberExpression)((SimpleBinaryExpression)(h.Body)).Right).Expression 
{value(WindowsFormsApplication6.Form1+<>c__DisplayClass0)} 
    CanReduce: false 
    DebugView: ".Constant<WindowsFormsApplication6.Form1+<>c__DisplayClass0>(WindowsFormsApplication6.Form1+<>c__DisplayClass0)" 
    NodeType: Constant 
    Type: {Name = "<>c__DisplayClass0" FullName = "WindowsFormsApplication6.Form1+<>c__DisplayClass0"} 
    Value: {WindowsFormsApplication6.Form1.} 
     } 
    } 

昔ながら2に出てくる:

((SimpleBinaryExpression)(j.Body)).Right 
{2} 
    CanReduce: false 
    DebugView: "2" 
    NodeType: Constant 
    Type: {Name = "Int32" FullName = "System.Int32"} 
    Value: 2 

は、だから私にはありませんそれがあなたを助けるかどうかを知ってください。親ノード、または親ノードがアクセスしているオブジェクトのタイプを調べることで、何かを伝えることができます。しかし、そのリンク式 - あなたは

user => user.Email == email 

あなたは、パラメータに渡されたに等しい電子メールですべてのユーザーを探しわけ言うので

- あなたの明確化の結果として追加


全く異なるものを意味します。あなたが言いたいこと

Expression<Func<User, string, bool>> (user, email) => user.Email == email 

電子メールは、今、パラメータになりますこの方法です。あなたが好きではない場合は、他にもできることが1つあります。

2番目の例は正常に動作します。追加のパラメータは必要ありません。constはconstになります。

t => t.Status != TaskStatus.Done && t.Status != TaskStatus.Failed 

編集:別の方法を追加: - 一種の不格好です

あなたのコードが動作を取得するためにしなければならなかったことのだから、1は、ラムダ外の文字列の電子メールを宣言しました。

通常、静的クラスのような特定の場所にパラメータを配置することで、パラメータをよりよく識別できます。ラムダを通過するときには、恐ろしいクロトールオブジェクトを見る必要はありませんが、あなたの作った素晴らしい静的なクラスです。

public static class Parameter 
{ 
    public static T Input<T>(string name) 
    { 
     return default(T); 
    } 
} 

次に、あなたのコードは次のようになります。

Expression<Func<User, bool>> exp = x => x.Email == Parameter.Input<String>("email"); 

その後、ツリーを走査することができます - あなたがタイプと名前(を見ることができます。パラメータ静的クラスへの呼び出しに来たときに議論のコレクションの中で)そしてあなたは行く...

+0

私は親ノードを見て、それが私を得るのを見てみましょう!ありがとう。私はここに私の調査結果を掲載します! –

+0

もう一度 - 何が起こっているのかは...ローカルユーザーが定義されていて、そのインスタンスをクロージャーとしてプルしようとしていますか?あなたがしたいことがあるのは、Expression > x => x.email == emailです。私はあなたがローカルインスタンスと望ましい入力の間で混乱している可能性があると思いますか? – Neil

+0

問題を明確にするために、もう少し質問に追加しました。私はまだ親ノードを見て、それが私を得るところを見ます。 –

0

ちょうどConstantExpressionのタイプをチェックしてください。任意の「定数」ConstantExpressionにはプリミティブ型があります。

関連する問題