Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Given a Member Access lambda expression, convert it to a specific string representation with full access path

Tags:

c#

.net

linq

Given an

Expression<Func<T, object>> 

(e.g. x => x.Prop1.SubProp), I want to create a string "Prop1.SubProp" for as deep as necessary.

In the case of a single access (e.g. x => x.Prop1), I can easily do this with:

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

However, if there is deeper nesting, e.g. x => x.Prop1.SubProp1, this only gets the most deeply nested name, e.g. "SubProp1" instead of "Prop1.SubProp1"

Is there anyway to access the full property path of a lambda expression?

like image 796
Nathan Avatar asked Jun 15 '10 23:06

Nathan


People also ask

How do you convert lambda expressions?

To convert a lambda expression to a named methodMove to the labda expression you want to convert. From the Refactor menu of the VisualAid choose To Named Method. Telerik® JustCode™ will replace the lambda expression with a method group and will add a new method.

What is lambda expression in C# with example?

The expression num => num * 5 is a lambda expression. The => operator is called the "lambda operator". In this example, num is an input parameter to the anonymous function, and the return value of this function is num * 5 . So when multiplyByFive is called with a parameter of 7 , the result is 7 * 5 , or 35 .

What is lambda expression in Linq?

The term 'Lambda expression' has derived its name from 'lambda' calculus which in turn is a mathematical notation applied for defining functions. Lambda expressions as a LINQ equation's executable part translate logic in a way at run time so it can pass on to the data source conveniently.

How do you read lambda expressions?

All lambda expressions use the lambda operator =>, which is read as "goes to". The left side of the lambda operator specifies the input parameters (if any) and the right side hold the expression or statement block. The lambda expression x => x * 2 is read "x goes to 2 times x." This reduced the no.


3 Answers

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());
}
like image 168
LukeH Avatar answered Oct 16 '22 10:10

LukeH


Take a look at my answer to this question.

Pretty much the same as what LukeH posted, with one additional feature:

If you have a type, say, MyClass, with a property MyProperty of type int, you could write this:

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

Here the expression e.Body is not a MemberExpression so the simple while (me != null) me = me.Expression as MemberExpression won't work.

The solution is to check additionally if it's a UnaryExpression with NodeType == Convert or ConvertChecked.

There may be other scenarios to account for; but for simple chains of property expressions, this approach works pretty well.

like image 28
Dan Tao Avatar answered Oct 16 '22 10:10

Dan Tao


You can use a project I have created to convert lambda to javascript: lambda2js

When using only properties and indexers, the result should be exactly what you need.

Example 1: Single property path

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

Example 2: Path containing indexer of a string dictionary

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

Example 3: Complex path containing indexers and multiple levels

Expression<Func<MyClass, object>> expr = x => x.SomeProp["Miguel"].Subprop[0].A.B;
var js = expr.CompileToJavascript();
// returns: SomeProp["Miguel"].Subprop[0].A.B
like image 25
Miguel Angelo Avatar answered Oct 16 '22 09:10

Miguel Angelo