从lambda表达式中获取属性名称

598

有没有更好的方法在通过lambda表达式传递属性名时获取属性名?以下是我目前拥有的代码。

例如:

GetSortingInfo<User>(u => u.UserId);

只有当属性是字符串时,将其转换为成员表达式才会起作用。因为并非所有属性都是字符串,所以我不得不使用对象,但这样对于那些属性将返回一元表达式。

public static RouteValueDictionary GetInfo<T>(this HtmlHelper html, 
    Expression<Func<T, object>> action) where T : class
{
    var expression = GetMemberInfo(action);
    string name = expression.Member.Name;

    return GetInfo(html, name);
}

private static MemberExpression GetMemberInfo(Expression method)
{
    LambdaExpression lambda = method as LambdaExpression;
    if (lambda == null)
        throw new ArgumentNullException("method");

    MemberExpression memberExpr = null;

    if (lambda.Body.NodeType == ExpressionType.Convert)
    {
        memberExpr = 
            ((UnaryExpression)lambda.Body).Operand as MemberExpression;
    }
    else if (lambda.Body.NodeType == ExpressionType.MemberAccess)
    {
        memberExpr = lambda.Body as MemberExpression;
    }

    if (memberExpr == null)
        throw new ArgumentException("method");

    return memberExpr;
}

2
我已经根据您的评论进行了更新;但是使用lambda获取字符串以便使用动态LINQ似乎是在反其道而行之...如果您使用lambda,请继续使用lambda ;-p 您不必一步完成整个查询 - 您可以使用“常规/lambda” OrderBy,“动态LINQ/string” Where等。 - Marc Gravell
2
可能是 get-property-name-and-type-using-lambda-expression 的重复问题。 - nawfal
5
з»ҷеӨ§е®¶дёҖдёӘжҸҗзӨәпјҡеҸӘдҪҝз”ЁжӯӨеӨ„еҲ—еҮәзҡ„MemberExpressionж–№жі•иҺ·еҸ–жҲҗе‘ҳзҡ„еҗҚз§°пјҢиҖҢдёҚжҳҜиҺ·еҸ–е®һйҷ…зҡ„MemberInfoжң¬иә«пјҢеӣ дёәеңЁжҹҗдәӣвҖңжҙҫз”ҹ:еҹәзЎҖвҖқеңәжҷҜдёӯпјҢиҝ”еӣһзҡ„MemberInfoдёҚиғҪдҝқиҜҒжҳҜеҸҚе°„зұ»еһӢгҖӮиҜҰи§Ғlambda-expression-not-returning-expected-memberinfoгҖӮжӣҫз»Ҹи®©жҲ‘зҠҜдәҶй”ҷгҖӮжҺҘеҸ—зҡ„зӯ”жЎҲд№ҹеӯҳеңЁжӯӨй—®йўҳгҖӮ - nawfal
1
@nawfal 猜测你的意思是“派生”。 - George Birbilis
4
从C# 6开始,您可以直接使用nameof(),例如:nameof(User.UserId)。不需要任何辅助方法,它在编译时被替换! - S.Serpooshan
显示剩余3条评论
23个回答

2
static void Main(string[] args)
{
    var prop = GetPropertyInfo<MyDto>(_ => _.MyProperty);

    MyDto dto = new MyDto();
    dto.MyProperty = 666;

    var value = prop.GetValue(dto);
    // value == 666
}

class MyDto
{
    public int MyProperty { get; set; }
}

public static PropertyInfo GetPropertyInfo<TSource>(Expression<Func<TSource, object>> propertyLambda)
{
    Type type = typeof(TSource);

    var member = propertyLambda.Body as MemberExpression;
    if (member == null)
    {
        var unary = propertyLambda.Body as UnaryExpression;
        if (unary != null)
        {
            member = unary.Operand as MemberExpression;
        }
    }
    if (member == null)
    {
        throw new ArgumentException(string.Format("Expression '{0}' refers to a method, not a property.",
            propertyLambda.ToString()));
    }

    var propInfo = member.Member as PropertyInfo;
    if (propInfo == null)
    {
        throw new ArgumentException(string.Format("Expression '{0}' refers to a field, not a property.",
            propertyLambda.ToString()));
    }

    if (type != propInfo.ReflectedType && !type.IsSubclassOf(propInfo.ReflectedType))
    {
        throw new ArgumentException(string.Format("Expression '{0}' refers to a property that is not from type {1}.",
            propertyLambda.ToString(), type));
    }

    return propInfo;
}

2

我已经更新了@Cameron的答案,以包含一些针对Convert类型lambda表达式的安全检查:

PropertyInfo GetPropertyName<TSource, TProperty>(
Expression<Func<TSource, TProperty>> propertyLambda)
{
  var body = propertyLambda.Body;
  if (!(body is MemberExpression member)
    && !(body is UnaryExpression unary
      && (member = unary.Operand as MemberExpression) != null))
    throw new ArgumentException($"Expression '{propertyLambda}' " +
      "does not refer to a property.");

  if (!(member.Member is PropertyInfo propInfo))
    throw new ArgumentException($"Expression '{propertyLambda}' " +
      "refers to a field, not a property.");

  var type = typeof(TSource);
  if (!propInfo.DeclaringType.GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
    throw new ArgumentException($"Expresion '{propertyLambda}' " + 
      "refers to a property that is not from type '{type}'.");

  return propInfo;
}

1

假设(TModel作为类)

Expression<Func<TModel, TValue>> expression

使用以下代码检索属性名称:

expression.GetPropertyInfo().Name;

扩展函数:

public static PropertyInfo GetPropertyInfo<TType, TReturn>(this Expression<Func<TType, TReturn>> property)
{
  LambdaExpression lambda = property;
  var memberExpression = lambda.Body is UnaryExpression expression
      ? (MemberExpression)expression.Operand
      : (MemberExpression)lambda.Body;

  return (PropertyInfo)memberExpression.Member;
}

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