Search code examples
c#expression-treesanonymous-typesc#-7.0

Is there a cleaner way to set Properties of Generic Classes?


Here's what I have so far, it works fine. Im just wondering if there is a smoother way to go about it:

    public static PropertyInfo GetProperty<T, T2>(this Expression<Func<T, T2>> selectorExpression)
    {
        var memberExpression = selectorExpression.Body as MemberExpression;
        if (memberExpression == null) throw new InvalidCastException();

        return memberExpression.Member as PropertyInfo;
    }

Here's an example function that can use it now. This one will set all selected values of objects in a list to something.

    public static List<T> Set<T,T2>(this List<T> inList, decimal amount, Expression<Func<T, decimal>> valueSelector)
        where T : class
    {
        var valueProperty = valueSelector.GetProperty();

        foreach (var item in inList)
        {
            valueProperty.SetValue(item, amount);
        }

        return inList
    }

Then I can simply just do this:

myList.Set(100, i => i.Value);

Where Value is some Setter property of the objects in MyList.

Now I know that second function is a super simple example. I am actually using GetProperty for way more complex stuff, specifically I have written a function that divies up a value amongst an IEnumerable to a selected setter property, based on a Getter 'weight' property in it.

The main thing I want to be discussing is my GetProperty function itself. Is there a better way to go about this or am I on the right track here already? Any kinds of further null checking or something I should be doing?


Solution

  • This works for me:

    public static PropertyInfo GetProperty<T>(this Expression<Func<T, decimal>> selectorExpression)
    {
        var memberExpression = selectorExpression.Body as MemberExpression;
        if (memberExpression == null) throw new InvalidCastException();
        return memberExpression.Member as PropertyInfo;
    }
    

    Then, with this code, I get 42 written to the console:

    void Main()
    {
        Expression<Func<Foo, decimal>> exp = q => q.Bar;
        var p = exp.GetProperty();
    
        var f = new Foo();
        p.SetValue(f, 42m);
        Console.WriteLine(f.Bar);
    }
    
    public class Foo
    {
        public decimal Bar { get; set; }
    }