Search code examples
c#lambdaexpression-trees

Would an expression tree work here?


I have the below method that I currently use to get the DB length of certain string fields (each property has an attribute called MetaDataFieldAttribute). It seems to work nicely however it's very 'stringly' typed with the property name.

     public static void Main(string[] args)
        {
            ...
            obj.PropertyName = str.TrimIfRequired(obj, "PropertyName");
        }

        public static string TrimIfRequired(this string str, object obj, string property)
        {
            var pi = obj.GetType().GetProperty(property);
            var attribute = pi.GetCustomAttributes<MetaDataFieldAttribute>().FirstOrDefault();
            if (attribute == null) return str;

            int length = attribute.Precision;
            return str.Length > length ? str.Substring(0, length) : str;
        }

I have a fairly basic understanding of expression trees, and my initial thought is that I could make the object/parameter of the method strongly typed rather than just passing through the string. Is this possible?


Solution

  • Yeah, you can use Expressions here just to get strong typing for property names, so instead of writing property name as string, you can use expression with property access, and then code will get MemberInfo item for specific property from expression and will get attribute from here. So if you change propertyName in the future, this part won't compile as it will be strong typed.

    here is working sample on .NetFiddle - https://dotnetfiddle.net/qYOfhE

    And here is the code itself:

    using System;
    using System.Linq;
    using System.Linq.Expressions;
    
    public class Program
    {
        public static void Main(string[] args)
        {
            var str = "TestTestTest";
    
            var propertyName = str.TrimIfRequired<Customer>((c) => c.FirstName);
            var propertyNameValue = str.TrimIfRequired<Customer>((c) => c.Age);
            Console.WriteLine(propertyName);
            Console.WriteLine(propertyNameValue);
        }
    }
    
    public static class Extensions
    {
        public static string TrimIfRequired<T>(this string str, Expression<Func<T, object>> expr)
        {
            var me = expr.Body as MemberExpression;
            if (me == null && expr.Body is UnaryExpression)
            {
                me = ((UnaryExpression) expr.Body).Operand as MemberExpression;
            }
    
            if (me == null)
            {
                throw new ArgumentException("Invalid expression. It should be MemberExpression");
            }
    
            var pi = me.Member;
            var attribute = pi.GetCustomAttributes(typeof(MetaDataFieldAttribute), false).FirstOrDefault() as MetaDataFieldAttribute;
            if (attribute == null) return str;
    
            int length = attribute.Precision;
            return str.Length > length ? str.Substring(0, length) : str;
        }
    }
    
    public class Customer
    {
        [MetaDataField(Precision = 6)]
        public string FirstName { get; set; }
    
        [MetaDataField(Precision = 2)]
        public int Age { get; set; }
    }
    
    
    public class MetaDataFieldAttribute : Attribute
    {
        public int Precision { get; set; }
    }