Search code examples
c#lambdaexpression-trees

Using lambda expression to get property OR type name


How can I adapt the method below to work when the lambda expression refers to the actual instance itself?

e.g. instead of

x => x.Name

the expression is

x => x

so if I had some class "Car" I could return the string "Car" instead of only being able to operate on its properties (e.g. Car.Colour)

The method:

public static string GetMemberName(Expression expression)
    {
        if (expression is LambdaExpression)
            expression = ((LambdaExpression)expression).Body;

        if (expression is MemberExpression)
        {
            var memberExpression = (MemberExpression)expression;
            if (memberExpression.Expression.NodeType ==
                ExpressionType.MemberAccess)
            {
                return GetMemberName(memberExpression.Expression)
                       + "."
                       + memberExpression.Member.Name;
            }
            return memberExpression.Member.Name;
        }


        if (expression is UnaryExpression)
        {
            var unaryExpression = (UnaryExpression)expression;

            if (unaryExpression.NodeType != ExpressionType.Convert)
                throw new Exception(string.Format(
                    "Cannot interpret member from {0}",
                    expression));
            return GetMemberName(unaryExpression.Operand);
        }
        throw new Exception(string.Format(
            "Could not determine member from {0}",
            expression));
    }

i.e. I want something like:

if (expression is SomeExpressionThatReturnsAnInstance)
{
    return (name of type of instance);
}

Solution

  • I've traced this back to the construction of the Expression. It doesn't really contain any instance information, and no way to get the type name.

    static Expression<Func<object, object>> thisObject = x => x;
    

    So there's no way that a type name can be derived from an Expression that doesn't even have a type (other than object).

    The method used to generate an expression that returns a property name:

    LambdaExpression BuildExpression(Type rootType, string propertyName)
        {
            try
            {
                var properties = propertyName.Split('.');
                ParameterExpression arg = Expression.Parameter(rootType, "x");
                Expression expr = arg;
                foreach (string property in properties)
                {
                    PropertyInfo propertyInfo = rootType.GetProperty(property);
                    if (propertyInfo == null)
                        return null;
                    expr = Expression.Property(expr, propertyInfo);
                    rootType = propertyInfo.PropertyType;
                }
                return Expression.Lambda(expr, arg);
            }
            catch (System.Exception ex)
            {
                return null;
            }
        }