Retrieving Property name from lambda expression

前端 未结 21 1685
迷失自我
迷失自我 2020-11-21 11:12

Is there a better way to get the Property name when passed in via a lambda expression? Here is what i currently have.

eg.

GetSortingInfo         


        
相关标签:
21条回答
  • 2020-11-21 11:50

    With C# 7 pattern matching:

    public static string GetMemberName<T>(this Expression<T> expression)
    {
        switch (expression.Body)
        {
            case MemberExpression m:
                return m.Member.Name;
            case UnaryExpression u when u.Operand is MemberExpression m:
                return m.Member.Name;
            default:
                throw new NotImplementedException(expression.GetType().ToString());
        }
    }
    

    Example:

    public static RouteValueDictionary GetInfo<T>(this HtmlHelper html, 
        Expression<Func<T, object>> action) where T : class
    {
        var name = action.GetMemberName();
        return GetInfo(html, name);
    }
    

    [Update] C# 8 pattern matching:

    public static string GetMemberName<T>(this Expression<T> expression) =>
        expression.Body switch
        {
            MemberExpression m =>
                m.Member.Name,
            UnaryExpression u when u.Operand is MemberExpression m =>
                m.Member.Name,
            _ =>
                throw new    NotImplementedException(expression.GetType().ToString())
        };
    
    0 讨论(0)
  • 2020-11-21 11:51

    Here's an update to method proposed by Cameron. The first parameter is not required.

    public PropertyInfo GetPropertyInfo<TSource, TProperty>(
        Expression<Func<TSource, TProperty>> propertyLambda)
    {
        Type type = typeof(TSource);
    
        MemberExpression member = propertyLambda.Body as MemberExpression;
        if (member == null)
            throw new ArgumentException(string.Format(
                "Expression '{0}' refers to a method, not a property.",
                propertyLambda.ToString()));
    
        PropertyInfo 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(
                "Expresion '{0}' refers to a property that is not from type {1}.",
                propertyLambda.ToString(),
                type));
    
        return propInfo;
    }
    

    You can do the following:

    var propertyInfo = GetPropertyInfo<SomeType>(u => u.UserID);
    var propertyInfo = GetPropertyInfo((SomeType u) => u.UserID);
    

    Extension methods:

    public static PropertyInfo GetPropertyInfo<TSource, TProperty>(this TSource source,
        Expression<Func<TSource, TProperty>> propertyLambda) where TSource : class
    {
        return GetPropertyInfo(propertyLambda);
    }
    
    public static string NameOfProperty<TSource, TProperty>(this TSource source,
        Expression<Func<TSource, TProperty>> propertyLambda) where TSource : class
    {
        PropertyInfo prodInfo = GetPropertyInfo(propertyLambda);
        return prodInfo.Name;
    }
    

    You can:

    SomeType someInstance = null;
    string propName = someInstance.NameOfProperty(i => i.Length);
    PropertyInfo propInfo = someInstance.GetPropertyInfo(i => i.Length);
    
    0 讨论(0)
  • 2020-11-21 11:53

    now in C# 6 you can simply use nameof like this nameof(User.UserId)

    which has many benefits, among them is that this is done at compile time, not runtime.

    https://msdn.microsoft.com/en-us/magazine/dn802602.aspx

    0 讨论(0)
  • 2020-11-21 11:58

    I've updated @Cameron's answer to include some safety checks against Convert typed lambda expressions:

    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;
    }
    
    0 讨论(0)
  • 2020-11-21 11:59

    This might be optimal

    public static string GetPropertyName<TResult>(Expression<Func<TResult>> expr)
    {
        var memberAccess = expr.Body as MemberExpression;
        var propertyInfo = memberAccess?.Member as PropertyInfo;
        var propertyName = propertyInfo?.Name;
    
        return propertyName;
    }
    
    0 讨论(0)
  • 2020-11-21 11:59
    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;
    }
    
    0 讨论(0)
提交回复
热议问题