Search code examples
c#.net-4.0expression-trees

Get MemberAssignments from Action


I'm trying to build a method that can capture assignments from a strongly-typed statement body. The method call should look something like this:

myObject.Assign(o =>
                {
                    o.SomeProperty = 1;
                    o.AnotherProperty = "two";
                });

I'd like to get a list of assignments; an array of MemberAssignment instances seems fitting.

It's unclear to me what the method header of Assign() needs to look like.

Here's what I currently have:

public class MyClass
{
    public void Assign(System.Linq.Expressions.Expression<System.Action<MyBunchOfProps>> assignments)
    {

    }
}

public struct MyBunchOfProps
{
    public int SomeProperty { get; set; }
    public string AnotherProperty { get; set; }
}

With a statement body and multiple assignments, I get "A lambda expression with a statement body cannot be converted to an expression tree".

If I omit the statement body and only do one assignment (myObject.Assign(o => o.SomeProperty = 1);), I instead get "An expression tree may not contain an assignment operator".

Do I need to use a different class rather than Expression?


Solution

  • It would be easy to analyze an expression-tree containing a bunch of assignments, but unfortunately, C# doesn't support the creation of expression-trees with assignments or statements through lambdas yet, as the compiler errors indicate.

    I suggest you construct a custom object that can hold a list of (member access lambda, object) tuples and use that instead.

    For example, you should be able to create a class that would allow for this syntax:

    var list = new AssignmentList<MyBunchOfProps>
               {
                   { o => o.SomeProperty, 1 },
                   { o => o.AnotherProperty,  "two" }
               };
    

    Here's an example implementation for this:

    public class AssignmentList<T> : IEnumerable<Tuple<LambdaExpression, object>>
    {
        private readonly List<Tuple<LambdaExpression, object>> _list 
                = new List<Tuple<LambdaExpression, object>>();
    
        public void Add<TProperty>(Expression<Func<T, TProperty>> selector, TProperty value)
        {
            _list.Add(Tuple.Create<LambdaExpression, object>(selector, value));       
        }
    
        public IEnumerator<Tuple<LambdaExpression, object>> GetEnumerator()
        {
            return _list.GetEnumerator();
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        { 
            return GetEnumerator();
        }
    }