29

与えられた

Expression<Func<T, object>> 

(例えばx => x.Prop1.SubProp)私は必要に応じてできるだけ深い文字列 "Prop1.SubProp"を作成したいです。

単一アクセスの場合(例:x => x.Prop1)、私は簡単にこれを行うことができます:

MemberExpression body = (expression.Body.NodeType == ExpressionType.Convert) ? (MemberExpression)((UnaryExpression)expression.Body).Operand : (MemberExpression)expression.Body;
return body.Member.Name;

ただし、より深いネスティングがある場合は、 x => x.Prop1.SubProp1、これは最も深くネストされた名前のみを取得します。 「Prop1.SubProp1」の代わりの「SubProp1」

ラムダ式のフルプロパティパスにアクセスする方法はありますか?


  • MemberExpression.Expressionを見てください。それらがすべてMemberExpressionインスタンスである限り、式ツリーを再帰的に歩くためにおそらくそれを使うことができます。 - Dan Bryant
  • 「承認された回答」を選択するのが大変でした。両方とも良かったです。この質問を見ている人は誰でも、LukeHとDan Taoの両方からの答えを見ることをお勧めします。 - Nathan
  • の可能な重複式< Func< TModel、TProperty>>からプロパティを文字列として取得します。 - nawfal

3 답변


34

public string GetPath<T>(Expression<Func<T, object>> expr)
{
    var stack = new Stack<string>();

    MemberExpression me;
    switch (expr.Body.NodeType)
    {
        case ExpressionType.Convert:
        case ExpressionType.ConvertChecked:
            var ue = expr.Body as UnaryExpression;
            me = ((ue != null) ? ue.Operand : null) as MemberExpression;
            break;
        default:
            me = expr.Body as MemberExpression;
            break;
    }

    while (me != null)
    {
        stack.Push(me.Member.Name);
        me = me.Expression as MemberExpression;
    }

    return string.Join(".", stack.ToArray());
}


  • +1:偉大な心は似ていると思う!ちょっとしたこと:これが本当に定義されるべきだと思わないでくださいGetPath<T, TProperty>(Expression<Func<T, TProperty>> expr)?さもなければあなたはほとんどいつもそれにぶつかるだろうConvert/ConvertCheckedシナリオ - 引数が不必要にキャストされているからです。 (または何かが足りない?) - Dan Tao
  • @ダン:うん、私は同意する。実際、私の編集の前に私はGetPath<T,U>(Expression<Func<T,U>> expr)。質問に示されている表現と一致するように変更しました。私はそれを現状のままにしておきます、そして、私はOPが彼らが好む署名を選ぶことができると思います - メソッド本体のコードはどちらの方法でも同じままです。 - LukeH
  • どのようにこれを修正して、インデックス(角括弧)演算子を含む式で動作するようにするかという考えはありますか? - joelmdev

6

私の答えを見てみましょうこの質問

LukeHが投稿したものとほぼ同じですが、1つの追加機能があります。

あなたがタイプを持っているなら、言うMyClassプロパティ付きMyPropertyタイプのint、あなたはこれを書くことができます:

Expression<Func<MyClass, object>> e = x => x.MyProperty;

ここではe.BodyですではないあるMemberExpressionとても簡単while (me != null) me = me.Expression as MemberExpressionうまくいきません。

解決策がそれであるかどうかをさらに確認することです。UnaryExpressionNodeType == ConvertまたはConvertChecked

説明するシナリオは他にもあります。しかし、単純な一連のプロパティ式の場合、この方法は非常にうまく機能します。


  • 私はちょうど私の答えを編集していますConvert/ConvertChecked編集したとき - LukeH
  • @LukeH:私は何を言うことができますか?明らかにあなたは自分がしていることを知っています;) - Dan Tao

0

私が作成したプロジェクトを使用して、ラムダをJavaScriptに変換することができます。lambda2js

プロパティとインデクサーのみを使用する場合、結果は正確にあなたが必要とするものであるべきです。

例1:単一プロパティパス

Expression<Func<MyClass, object>> expr = x => x.Phone;
var js = expr.CompileToJavascript();
// returns: Phone

例2:文字列辞書のインデクサーを含むパス

Expression<Func<MyClass, object>> expr = x => x.PhonesByName["Miguel"];
var js = expr.CompileToJavascript();
// returns: PhonesByName["Miguel"]

例3:インデクサーと複数レベルを含む複合パス

Expression<Func<MyClass, object>> expr = x => x.SomeProp["Miguel"].Subprop[0].A.B;
var js = expr.CompileToJavascript();
// returns: SomeProp["Miguel"].Subprop[0].A.B

リンクされた質問


関連する質問

最近の質問