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?
eg. instead
x => x.Name
expression
x => x
so if I had some kind of class "Car" I could return the string "Car" and not only work with its properties (eg Car.Colour)
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 need something like:
if (expression is SomeExpressionThatReturnsAnInstance)
{
return (name of type of instance);
}
source to share
I've traced this back to building the expression. It does not contain any information about the instance and has no way of getting the type name.
static Expression<Func<object, object>> thisObject = x => x;
So there is no way that a type name can be inferred from an expression that doesn't even have a type (other than an object).
Method used to create an expression that returns the name of the property:
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;
}
}
source to share
I may be wrong, but it x => x
will be direct ParameterExpression
. Just add an additional test to your existing test is MemberExpression
:
if (expression is MemberExpression)
{
// As-is
}
// New condition
if (expression is ParameterExpression)
{
return expression.Type.Name;
}
Using this code:
class Car { public string Color { get; set; }}
Expression<Func<Car, string>> expr1 = x => x.Color;
Expression<Func<Car, Car>> expr2 = x => x;
Console.WriteLine(GetMemberName(expr1));
> Color
Console.WriteLine(GetMemberName(expr2));
> Car
source to share
If you are sure that an expression like x => x, so you don't even need to see in the body, just get parameters like
((LambdaExpression)expression).Parameters.First().Type.Name
also you can add a condition like
if(expression is ParameterExpression){
return ((ParameterExpression)expression).Type
}
source to share
//Use generics for more information!
public static string GetMemberName<T, TValue>(Expression<Func<T, TValue>> 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;
}
//Magic part...
if (typeof(T) == typeof(TValue))
{
return typeof(T).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));
}
source to share