使用lambda表达式获取属性或类型名称

3
我可以将下面的方法修改以使得 lambda 表达式引用实际实例自身时也能正常工作,您需要使用以下代码,而不是:
x => x.Name

表达式是

x => x

如果我有一个类“Car”,我可以返回字符串“Car”,而不仅仅是操作它的属性(例如Car.Colour)。

这个方法:

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));
    }

我希望你能够提供一些类似以下的东西:

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

你想要返回 object 而不是 property,是吗? - Dhrumil
不,我想要对象类型的名称,例如“汽车”。 - Mathew
@TyCobb - 不,目前我只有一个表达式。x.ToString() 返回 "x => x",而 x.GetType().Name 返回 "Expression`1"。 - Mathew
2
GetMemberName 是从哪里调用的?我认为你甚至不需要这个表达式。你可以使用 TypeOf(T),其中 T 是 x 的类型,假设你像通常一样调用它。 - Euphoric
GetMemberName被调用并作用于一组自定义类型的列表,这些类型代表一个错误,每个错误都包含一个LambdaExpression属性(命名为“Property”)。因此,它被这样调用:GetMemberName(myCustomError.Property)。有时,“Property”指向实际的成员,有时则指向类型本身。 - Mathew
显示剩余4条评论
4个回答

1
我可能误解了,但直接使用 x => x 会成为一个 ParameterExpression。只需在您现有的 is MemberExpression 测试下添加一个额外的测试即可:
if (expression is MemberExpression)
{
    // As-is
}
// New condition
if (expression is ParameterExpression)
{
    return expression.Type.Name;
}

使用此代码:
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));

汽车

我认为在OP x => x 中应该是_x而不是_()=>x,因此你的解决方案可能是错误的。 - Grundy
expression.NodeType 是 ExpressionType.Lambda。 - Mathew

0

如果你确定表达式像x=>x,那么你甚至不需要查看主体,只需获取参数即可。

((LambdaExpression)expression).Parameters.First().Type.Name

你也可以添加条件,例如:

if(expression is ParameterExpression){
    return ((ParameterExpression)expression).Type
}

((LambdaExpression)expression).Parameters[0].Type.Name 返回值为 "Object"。 - Mathew
1
@Mathew 你怎么称呼它? - Grundy

0

我已将其追溯到表达式的构造。它实际上不包含任何实例信息,也没有获取类型名称的方式。

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

因此,无法从甚至没有类型(除了对象)的表达式中推导出类型名称。

生成返回属性名称的表达式所使用的方法:

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;
        }
    }

我不明白,你说像 x => x.Name 这样的代码可以工作。这是不可能的。 - svick
@Mathew,你怎么使用这个BuildExpression?你不能将LambdaExpression转换为Expression<Func<object, object>> - Grundy

0
//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));
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接