Elton Stoneman

  Home  |   Contact  |   Syndication    |   Login
  120 Posts | 0 Stories | 3600 Comments | 0 Trackbacks

News

Archives

Post Categories

[Source: http://geekswithblogs.net/EltonStoneman]

Supposing you’re using a lambda expression as a neat way to access a named property:

                s => s.FirstName

- when what you really want is to access it without using a string for the property name (“FirstName”), for example to specify the source or target property for a mapping exercise.

It’s easy if the expression is a direct property of the parameter type – a member of the “s” in the expression; casting the whole expression as a MemberExpression gives you access to the member as a PropertyInfo. You can encapsulate it in an extension method of LambdaExpression:

    public static PropertyInfo AsPropertyInfo(this LambdaExpression expression)

    {

        PropertyInfo info = null;

        if (expression.Body.NodeType == ExpressionType.MemberAccess)

        {

            info = ((MemberExpression)expression.Body).Member as PropertyInfo;

        }

        return info;

    }

- which lets you access the property like this:

    Expression<Func<FullUser, object>> exp = s => s.FirstName;

    PropertyInfo sourceProperty = exp.AsPropertyInfo();

But if the expression represents a property of a nested type, or a property of  a nested type of a nested type:

                s => s.Address.Line1

      s => s.Address.PostCode.Code

- then it’s different.

What you want in this case is an executable expression which will access the containing object of the property (e.g. get you the Address property of the source object, or the PostCode property of the Address property of the source object). You also want the PropertyInfo of the target property (e.g. Line1 or Code). And you want both the property accessor and the PropertyInfo from the same expression.

This is not too difficult. It doesn’t require a stack of target objects and PropertyInfos as originally feared. Firstly store the PropertyInfo from the nested target in the normal way:

    targetPropertyInfo = targetExpression.AsPropertyInfo();

- this gives us access to Line1 or Code. Then store the expression which retrieves the path to the containing object for the property from the original source - .Address  or .Address.Postcode. In the expression tree, this is the expression which contains the root to the original parameter:

    if (targetExpression.Body.NodeType == ExpressionType.MemberAccess)

    {

        MemberExpression memberExpression = targetExpression.Body as MemberExpression;

        if (memberExpression.Expression.NodeType != ExpressionType.Parameter)

        {

            ParameterExpression parameter = GetParameterExpression(memberExpression.Expression);

            if (parameter != null)

            {

                _targetExpression = Expression.Lambda(memberExpression.Expression, parameter);

            }

        }

    }

The key line is the one which contains Expression.Lambda(). The parent expression is a MemberExpression (e.g. s.Address, or s.Address.PostCode) which itself is not executable. You can’t compile a MemberExpression and execute it on an object to get the member, as the expression needs to know the parameter it executes against.

Expression.Lambda creates a compilable, executable expression against a provided target parameter – which we already have from the “s” of the original expression, and we can find for any level of nesting:

    private ParameterExpression GetParameterExpression(Expression expression)

    {

        while (expression.NodeType == ExpressionType.MemberAccess)

        {

            expression = ((MemberExpression)expression).Expression;

        }

        if (expression.NodeType == ExpressionType.Parameter)

        {

            return (ParameterExpression)expression;

        }

        return null;

    }

So now we have the PropertyInfo for the nested target, and an expression which will give us the nested target, we can set the target property value like this:

    object target; //this is the top-level object

    //...

    realTarget = expression.Compile().DynamicInvoke(target);

    targetPropertyInfo.SetValue(realTarget, value, null);

It’s quite a complex requirement, but the solution is straightforward and the complexity is isolated from the calling code. Note that the example code above only deals with nested properties, not expressions with mixed properties and method calls (e.g. s.Address.GetPostCode().InwardCode), but it’s straightforward to cover those cases too.


  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati
posted on Thursday, November 05, 2009 10:14 PM

Feedback

# re: Retrieving Nested Properties from Lambda Expressions 5/2/2010 3:35 PM hospedagem de Sites
Great post. Very enlightening. Congratulations.

# re: Retrieving Nested Properties from Lambda Expressions 6/14/2010 6:07 AM USANA-46
Very good post. It really helped me a lot, will be referring a lot of friends about this.I really enjoy reading your blog.The keyword sniping links are awesome.Keep it up.Thanks for sharing with us.Keep posting.

# re: Retrieving Nested Properties from Lambda Expressions 6/19/2010 12:13 PM breast cancer symptoms
little bit confusing, coz i'm totally beginner in scripting. anyway, your posting is good, i learn more on it.

# re: Retrieving Nested Properties from Lambda Expressions 6/19/2010 12:19 PM daily rosetta
Thanks for sharing with us, great post.

# re: Retrieving Nested Properties from Lambda Expressions 6/19/2010 12:22 PM juvenile rheumatoid arthritis
Is that PHP? recently i start to learn PHP, its little bit hard for me, since im new for them.

# re: Retrieving Nested Properties from Lambda Expressions 5/14/2011 12:00 AM charlotte pet sitting
great bro keep it up

# re: Retrieving Nested Properties from Lambda Expressions 6/5/2011 12:41 AM London Escorts
we will come back to see if you have any follow up topics ;-) London Indian escorts

# re: Retrieving Nested Properties from Lambda Expressions 7/16/2011 8:17 PM saga gold
Very good post. It really helped me a lot, will be referring a lot of friends about this.I really enjoy reading your blog.The keyword sniping links are awesome.Keep it up.Thanks for sharing with us.Keep posting.

# re: Retrieving Nested Properties from Lambda Expressions 7/17/2011 5:13 AM saga hair
Very good post.I really enjoy reading your blog.The keyword sniping links are awesome. It really helped me a lot, will be referring a lot of friends about this.Keep it up.Thanks for sharing with us.Keep posting.

# re: Retrieving Nested Properties from Lambda Expressions 7/20/2011 3:22 PM saga remy
Very good post.I really enjoy reading your blog. It really helped me a lot, will be referring a lot of friends about this.The keyword sniping links are awesome.Keep it up.Thanks for sharing with us.Keep posting.

# re: Retrieving Nested Properties from Lambda Expressions 7/23/2011 11:44 PM small business credit cards
yeah I am quite agree with you, its really very a good post
Thanks for sharing it with us
regards


# re: Retrieving Nested Properties from Lambda Expressions 8/25/2011 5:33 PM darrensy
This blog is very good and informative. It is difficult task but your post and experience serve and teach me how to handle and make it more simple and manageable
________________
custom wine label


# re: Retrieving Nested Properties from Lambda Expressions 10/12/2011 5:18 AM junies
I am currently searching for ways in which I could enhance my knowledge in this said topic you have posted here. It does help me a lot knowing that you have shared this information here freely. I love the way the people here interact and shared their opinions too. I would love to track your future posts pertaining to the said topic we are able to read. Cursos de ingles en el extranjero



# re: Retrieving Nested Properties from Lambda Expressions 12/14/2011 4:35 PM serial
Well done your script on my site! Thank you very much! I would go more often! Many tests done the all perfect! More such interesting posts from you !)))))

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: