Retrieving Property name from lambda expression

前端 未结 21 1725
迷失自我
迷失自我 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 12:00

    I"m using an extension method for pre C# 6 projects and the nameof() for those targeting C# 6.

    public static class MiscExtentions
    {
        public static string NameOf<TModel, TProperty>(this object @object, Expression<Func<TModel, TProperty>> propertyExpression)
        {
            var expression = propertyExpression.Body as MemberExpression;
            if (expression == null)
            {
                throw new ArgumentException("Expression is not a property.");
            }
    
            return expression.Member.Name;
        }
    }
    

    And i call it like:

    public class MyClass 
    {
        public int Property1 { get; set; }
        public string Property2 { get; set; }
        public int[] Property3 { get; set; }
        public Subclass Property4 { get; set; }
        public Subclass[] Property5 { get; set; }
    }
    
    public class Subclass
    {
        public int PropertyA { get; set; }
        public string PropertyB { get; set; }
    }
    
    // result is Property1
    this.NameOf((MyClass o) => o.Property1);
    // result is Property2
    this.NameOf((MyClass o) => o.Property2);
    // result is Property3
    this.NameOf((MyClass o) => o.Property3);
    // result is Property4
    this.NameOf((MyClass o) => o.Property4);
    // result is PropertyB
    this.NameOf((MyClass o) => o.Property4.PropertyB);
    // result is Property5
    this.NameOf((MyClass o) => o.Property5);
    

    It works fine with both fields and properties.

    0 讨论(0)
  • 2020-11-21 12:01
    public string GetName<TSource, TField>(Expression<Func<TSource, TField>> Field)
    {
        return (Field.Body as MemberExpression ?? ((UnaryExpression)Field.Body).Operand as MemberExpression).Member.Name;
    }
    

    This handles member and unary expressions. The difference being that you will get a UnaryExpression if your expression represents a value type whereas you will get a MemberExpression if your expression represents a reference type. Everything can be cast to an object, but value types must be boxed. This is why the UnaryExpression exists. Reference.

    For the sakes of readability (@Jowen), here's an expanded equivalent:

    public string GetName<TSource, TField>(Expression<Func<TSource, TField>> Field)
    {
        if (object.Equals(Field, null))
        {
            throw new NullReferenceException("Field is required");
        }
    
        MemberExpression expr = null;
    
        if (Field.Body is MemberExpression)
        {
            expr = (MemberExpression)Field.Body;
        }
        else if (Field.Body is UnaryExpression)
        {
            expr = (MemberExpression)((UnaryExpression)Field.Body).Operand;
        }
        else
        {
            const string Format = "Expression '{0}' not supported.";
            string message = string.Format(Format, Field);
    
            throw new ArgumentException(message, "Field");
        }
    
        return expr.Member.Name;
    }
    
    0 讨论(0)
  • 2020-11-21 12:01

    I created an extension method on ObjectStateEntry to be able to flag properties (of Entity Framework POCO classes) as modified in a type safe manner, since the default method only accepts a string. Here's my way of getting the name from the property:

    public static void SetModifiedProperty<T>(this System.Data.Objects.ObjectStateEntry state, Expression<Func<T>> action)
    {
        var body = (MemberExpression)action.Body;
        string propertyName = body.Member.Name;
    
        state.SetModifiedProperty(propertyName);
    }
    
    0 讨论(0)
  • 2020-11-21 12:02

    Well, there's no need to call .Name.ToString(), but broadly that is about it, yes. The only consideration you might need is whether x.Foo.Bar should return "Foo", "Bar", or an exception - i.e. do you need to iterate at all.

    (re comment) for more on flexible sorting, see here.

    0 讨论(0)
  • 2020-11-21 12:03

    I leave this function if you want to get multiples fields:

    /// <summary>
        /// Get properties separated by , (Ex: to invoke 'd => new { d.FirstName, d.LastName }')
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static string GetFields<T>(Expression<Func<T, object>> exp)
        {
            MemberExpression body = exp.Body as MemberExpression;
            var fields = new List<string>();
            if (body == null)
            {
                NewExpression ubody = exp.Body as NewExpression;
                if (ubody != null)
                    foreach (var arg in ubody.Arguments)
                    {
                        fields.Add((arg as MemberExpression).Member.Name);
                    }
            }
    
            return string.Join(",", fields);
        }
    
    0 讨论(0)
  • 2020-11-21 12:03

    Starting with .NET 4.0 you can use ExpressionVisitor to find properties:

    class ExprVisitor : ExpressionVisitor {
        public bool IsFound { get; private set; }
        public string MemberName { get; private set; }
        public Type MemberType { get; private set; }
        protected override Expression VisitMember(MemberExpression node) {
            if (!IsFound && node.Member.MemberType == MemberTypes.Property) {
                IsFound = true;
                MemberName = node.Member.Name;
                MemberType = node.Type;
            }
            return base.VisitMember(node);
        }
    }
    

    Here is how you use this visitor:

    var visitor = new ExprVisitor();
    visitor.Visit(expr);
    if (visitor.IsFound) {
        Console.WriteLine("First property in the expression tree: Name={0}, Type={1}", visitor.MemberName, visitor.MemberType.FullName);
    } else {
        Console.WriteLine("No properties found.");
    }
    
    0 讨论(0)
提交回复
热议问题