Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 787007
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 14, 20262026-05-14T21:08:01+00:00 2026-05-14T21:08:01+00:00

I use some strongly-typed expressions that get serialized to allow my UI code to

  • 0

I use some strongly-typed expressions that get serialized to allow my UI code to have strongly-typed sorting and searching expressions. These are of type Expression<Func<TModel,TProperty>> and are used as such: SortOption.Field = (p => p.FirstName);. I’ve gotten this working perfectly for this simple case.

The code that I’m using for parsing the “FirstName” property out of there is actually reusing some existing functionality in a third-party product that we use and it works great, until we start working with deeply-nested properties(SortOption.Field = (p => p.Address.State.Abbreviation);). This code has some very different assumptions in the need to support deeply-nested properties.

As for what this code does, I don’t really understand it and rather than changing that code, I figured I should just write from scratch this functionality. However, I don’t know of a good way to do this. I suspect we can do something better than doing a ToString() and performing string parsing. So what’s a good way to do this to handle the trivial and deeply-nested cases?

Requirements:

  • Given the expression p => p.FirstName I need a string of "FirstName".
  • Given the expression p => p.Address.State.Abbreviation I need a string of "Address.State.Abbreviation"

While it’s not important for an answer to my question, I suspect my serialization/deserialization code could be useful to somebody else who finds this question in the future, so it is below. Again, this code is not important to the question – I just thought it might help somebody. Note that DynamicExpression.ParseLambda comes from the Dynamic LINQ stuff and Property.PropertyToString() is what this question is about.

/// <summary>
/// This defines a framework to pass, across serialized tiers, sorting logic to be performed.
/// </summary>
/// <typeparam name="TModel">This is the object type that you are filtering.</typeparam>
/// <typeparam name="TProperty">This is the property on the object that you are filtering.</typeparam>
[Serializable]
public class SortOption<TModel, TProperty> : ISerializable where TModel : class
{
    /// <summary>
    /// Convenience constructor.
    /// </summary>
    /// <param name="property">The property to sort.</param>
    /// <param name="isAscending">Indicates if the sorting should be ascending or descending</param>
    /// <param name="priority">Indicates the sorting priority where 0 is a higher priority than 10.</param>
    public SortOption(Expression<Func<TModel, TProperty>> property, bool isAscending = true, int priority = 0)
    {
        Property = property;
        IsAscending = isAscending;
        Priority = priority;
    }

    /// <summary>
    /// Default Constructor.
    /// </summary>
    public SortOption()
        : this(null)
    {
    }

    /// <summary>
    /// This is the field on the object to filter.
    /// </summary>
    public Expression<Func<TModel, TProperty>> Property { get; set; }

    /// <summary>
    /// This indicates if the sorting should be ascending or descending.
    /// </summary>
    public bool IsAscending { get; set; }

    /// <summary>
    /// This indicates the sorting priority where 0 is a higher priority than 10.
    /// </summary>
    public int Priority { get; set; }

    #region Implementation of ISerializable

    /// <summary>
    /// This is the constructor called when deserializing a SortOption.
    /// </summary>
    protected SortOption(SerializationInfo info, StreamingContext context)
    {
        IsAscending = info.GetBoolean("IsAscending");
        Priority = info.GetInt32("Priority");

        // We just persisted this by the PropertyName. So let's rebuild the Lambda Expression from that.
        Property = DynamicExpression.ParseLambda<TModel, TProperty>(info.GetString("Property"), default(TModel), default(TProperty));
    }

    /// <summary>
    /// Populates a <see cref="T:System.Runtime.Serialization.SerializationInfo"/> with the data needed to serialize the target object.
    /// </summary>
    /// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> to populate with data. </param>
    /// <param name="context">The destination (see <see cref="T:System.Runtime.Serialization.StreamingContext"/>) for this serialization. </param>
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        // Just stick the property name in there. We'll rebuild the expression based on that on the other end.
        info.AddValue("Property", Property.PropertyToString());
        info.AddValue("IsAscending", IsAscending);
        info.AddValue("Priority", Priority);
    }

    #endregion
}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-14T21:08:01+00:00Added an answer on May 14, 2026 at 9:08 pm

    Here’s the trick: any expression of this form…

    obj => obj.A.B.C // etc.
    

    …is really just a bunch of nested MemberExpression objects.

    First you’ve got:

    MemberExpression: obj.A.B.C
    Expression:       obj.A.B   // MemberExpression
    Member:           C
    

    Evaluating Expression above as a MemberExpression gives you:

    MemberExpression: obj.A.B
    Expression:       obj.A     // MemberExpression
    Member:           B
    

    Finally, above that (at the “top”) you have:

    MemberExpression: obj.A
    Expression:       obj       // note: not a MemberExpression
    Member:           A
    

    So it seems clear that the way to approach this problem is by checking the Expression property of a MemberExpression up until the point where it is no longer itself a MemberExpression.


    UPDATE: It seems there is an added spin on your problem. It may be that you have some lambda that looks like a Func<T, int>…

    p => p.Age
    

    …but is actually a Func<T, object>; in this case, the compiler will convert the above expression to:

    p => Convert(p.Age)
    

    Adjusting for this issue actually isn’t as tough as it might seem. Take a look at my updated code for one way to deal with it. Notice that by abstracting the code for getting a MemberExpression away into its own method (TryFindMemberExpression), this approach keeps the GetFullPropertyName method fairly clean and allows you to add additional checks in the future — if, perhaps, you find yourself facing a new scenario which you hadn’t originally accounted for — without having to wade through too much code.


    To illustrate: this code worked for me.

    // code adjusted to prevent horizontal overflow
    static string GetFullPropertyName<T, TProperty>
    (Expression<Func<T, TProperty>> exp)
    {
        MemberExpression memberExp;
        if (!TryFindMemberExpression(exp.Body, out memberExp))
            return string.Empty;
    
        var memberNames = new Stack<string>();
        do
        {
            memberNames.Push(memberExp.Member.Name);
        }
        while (TryFindMemberExpression(memberExp.Expression, out memberExp));
    
        return string.Join(".", memberNames.ToArray());
    }
    
    // code adjusted to prevent horizontal overflow
    private static bool TryFindMemberExpression
    (Expression exp, out MemberExpression memberExp)
    {
        memberExp = exp as MemberExpression;
        if (memberExp != null)
        {
            // heyo! that was easy enough
            return true;
        }
    
        // if the compiler created an automatic conversion,
        // it'll look something like...
        // obj => Convert(obj.Property) [e.g., int -> object]
        // OR:
        // obj => ConvertChecked(obj.Property) [e.g., int -> long]
        // ...which are the cases checked in IsConversion
        if (IsConversion(exp) && exp is UnaryExpression)
        {
            memberExp = ((UnaryExpression)exp).Operand as MemberExpression;
            if (memberExp != null)
            {
                return true;
            }
        }
    
        return false;
    }
    
    private static bool IsConversion(Expression exp)
    {
        return (
            exp.NodeType == ExpressionType.Convert ||
            exp.NodeType == ExpressionType.ConvertChecked
        );
    }
    

    Usage:

    Expression<Func<Person, string>> simpleExp = p => p.FirstName;
    Expression<Func<Person, string>> complexExp = p => p.Address.State.Abbreviation;
    Expression<Func<Person, object>> ageExp = p => p.Age;
    
    Console.WriteLine(GetFullPropertyName(simpleExp));
    Console.WriteLine(GetFullPropertyName(complexExp));
    Console.WriteLine(GetFullPropertyName(ageExp));
    

    Output:

    FirstName
    Address.State.Abbreviation
    Age
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

1) How can I use strongly typed dictionaries? I have some in my codebehind
I'm trying to change over some ASP.NET code to use the strongly-typed translations we're
Just some architectural question: I use ASP.net MVC and exclusively rely on Strongly-Typed Views
I have a requirement to use business objects to call strongly typed table adapters
I have a question about the use of the strongly typed model in Razor
Folks, We are trying to use the strongly typed action link methods that look
I have an ASP.NET MVC 2 project that renders conventional strongly typed pages, but
i use some code for inline cell editing from Apples TaggedLocations Example and im
I use some code to encrypt & decrypt string in C# but i want
I'm modelling a list of strongly typed database keys. Some will be ints, some

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.