1

With databinding objects to controls and grids I hated how the property names would be magic strings, so I created a very simple method as follows:

public static string GetPropertyName<PropertyType>(Expression<Func<T, PropertyType>> expressionForProperty)
    {
        MemberExpression expression = expressionForProperty.Body as MemberExpression;
        return expression.Member.Name;
    }

This lets me use code such as:

Product.GetPropertyName(m => m.Name)

to return "Name".

This works perfectly for basic objects. However if I change the method call to be:

Product.GetPropertyName(m => m.ProductCategory.Name)

This also returns "Name". But in order for the databinding to work, I would need it to return "ProductCategory.Name". Is there a way I can get to this by changing the method "GetPropertyName"?

A possible workaround would be to do this:

string test = Product.GetPropertyName(p => p.ProductCategory) + "." + ProductCategory.GetPropertyName(pc => pc.Name)

However, this isn't a neat solution.

eyeballpaul
  • 1,725
  • 2
  • 25
  • 39
  • possible duplicate of [Get the property, as a string, from an Expression>](http://stackoverflow.com/questions/2789504/get-the-property-as-a-string-from-an-expressionfunctmodel-tproperty) – nawfal Oct 11 '13 at 19:11

2 Answers2

3

This is a modified version of something I might have found here on StackOVerflow:

public static class GetPropertyNameExtension
{
    public static string GetPropertyName<TArg, TProperty>(this Expression<Func<TArg, TProperty>> propertyExpression)
    {
        return propertyExpression.Body.GetMemberExpression().GetPropertyName();
    }

    public static string GetPropertyName<TProperty>(this Expression<Func<TProperty>> propertyExpression)
    {
        return propertyExpression.Body.GetMemberExpression().GetPropertyName();
    }

    public static string GetPropertyName(this MemberExpression memberExpression)
    {
        if (memberExpression == null)
        {
            return null;
        }

        if (memberExpression.Member.MemberType != MemberTypes.Property)
        {
            return null;
        }

        var child = memberExpression.Member.Name;
        var parent = GetPropertyName(memberExpression.Expression.GetMemberExpression());

        return parent == null ?
            child
            : parent + "." + child;
    }

    public static MemberExpression GetMemberExpression(this Expression expression)
    {
        if (expression is MemberExpression)
            return (MemberExpression)expression;

        if (expression is UnaryExpression)
            return (MemberExpression)((UnaryExpression)expression).Operand;

        return null;
    }
}
lightbricko
  • 2,649
  • 15
  • 21
  • Thanks I'll try this on Monday. A few minutes after posting this I came across a way to do it. I'll post it up once I get back to work. – eyeballpaul Jul 26 '13 at 19:05
  • Great stuff, just I would replace TProperty with object like this `public static string GetPropertyName(this Expression> propertyExpression)`, in such case you would not need to specify the property type when using the extension and that does not impact the rest of the code. – Giedrius Jan 14 '14 at 14:03
  • @Giedrius, The type is automatically inferred (assuming you use a MemberExpression). Hence you don't need to specify the type. This compiles: `string propertyName = someMemberExpression.GetPropertyName();` – lightbricko Jan 14 '14 at 15:05
  • It depends on how you're using it. My variation allows to write it like this: `criteria.Add(Restrictions.Eq(PropertyAccess.GetName(x => x.Category.Id), filter.CategoryId))`, as I don't have any product instances laying around yet, just wish to create criteria for selecting. – Giedrius Jan 14 '14 at 16:03
0

I came up with the following which seems to work:

public static string GetComplexPropertyName<PropertyType>(Expression<Func<T, PropertyType>> expressionForProperty)
{
    // get the expression body
    Expression expressionBody = expressionForProperty.Body as MemberExpression;

    string expressionAsString = null;

    // all properties bar the root property will be "convert"
    switch (expressionBody.NodeType)
    {
        case ExpressionType.Convert:
        case ExpressionType.ConvertChecked:

            UnaryExpression unaryExpression = expressionBody as UnaryExpression;

            if (unaryExpression != null)
            {
                expressionAsString = unaryExpression.Operand.ToString();
            }

            break;
        default:
            expressionAsString = expressionBody.ToString();
            break;
    }

    // makes ure we have got an expression
    if (!String.IsNullOrWhiteSpace(expressionAsString))
    {
        // we want to get rid of the first operand as it will be the root type, so get the first occurence of "."
        int positionOfFirstDot = expressionAsString.IndexOf('.');

        if (positionOfFirstDot != -1)
        {
            return expressionAsString.Substring(positionOfFirstDot + 1, expressionAsString.Length - 1 - positionOfFirstDot);
        }
    }

    return string.Empty;
}
nawfal
  • 70,104
  • 56
  • 326
  • 368
eyeballpaul
  • 1,725
  • 2
  • 25
  • 39