Creating a property setter delegate

前端 未结 4 569
误落风尘
误落风尘 2020-11-30 22:23

I have created methods for converting a property lambda to a delegate:

public static Delegate MakeGetter(Expression> propertyLam         


        
相关标签:
4条回答
  • 2020-11-30 22:54

    Action<T> represents a delegate that takes one parameter of type T and returns nothing. The lambda expressions you provide to MakeSetter represent delegates that take no parameter and return either SomeClass.SomeProperty or someObject.SomeProperty.

    The error messages you're getting are due to the fact that the compiler cannot infer the types from the lambda expressions you're passing into the MakeSetter method because what you've passed and what the method is expecting are not in sync.

    0 讨论(0)
  • 2020-11-30 23:02

    The Expression API supports this in .NET 4.0, but sadly the C# compiler doesn't add any extra candy to support. But the good news is that you can trivially take a "get" expression (which the C# compiler can write) and re-write it as a "set" expression.

    And even better; if you don't have .NET 4.0, there are still at least two other ways of performing a "set" via an expression written as a "get".

    Here they all are, for info:

    using System;
    using System.Linq.Expressions;
    using System.Reflection;
    class Foo {
        public string Bar { get; set; }
        static void Main() {
            // take a "get" from C#
            Expression<Func<Foo, string>> get = foo => foo.Bar;
    
            // re-write in .NET 4.0 as a "set"
            var member = (MemberExpression)get.Body;
            var param = Expression.Parameter(typeof(string), "value");
            var set = Expression.Lambda<Action<Foo, string>>(
                Expression.Assign(member, param), get.Parameters[0], param);
    
            // compile it
            var action = set.Compile();
            var inst = new Foo();
            action(inst, "abc");
            Console.WriteLine(inst.Bar); // show it working
    
            //==== reflection
            MethodInfo setMethod = ((PropertyInfo)member.Member).GetSetMethod();
            setMethod.Invoke(inst, new object[] { "def" });
            Console.WriteLine(inst.Bar); // show it working
    
            //==== Delegate.CreateDelegate
            action = (Action<Foo, string>)
                Delegate.CreateDelegate(typeof(Action<Foo, string>), setMethod);
            action(inst, "ghi");
            Console.WriteLine(inst.Bar); // show it working
        }
    }
    
    0 讨论(0)
  • 2020-11-30 23:03

    Your MakeSetter is expecting an Action<T> and you are passing it a Func<T> (() => someObject.SomeProperty). Try the following:

    Delegate setter = MakeSetter((prop) => {someObject.SomeProperty = prop;});
    setter.DynamicInvoke(new object[]{propValue});
    

    EDIT Doesn't look like you can convert statement lambdas into expressions. This is somewhat of a round about way to do it without expressions - straight to delegates:

    class Test2 {
        delegate void Setter<T>(T value);
    
        public static void Test() {
            var someObject = new SomeObject();
            Setter<string> setter = (v) => { t.SomeProperty = v; };
            setter.DynamicInvoke(new object[]{propValue});
        }
    }
    
    0 讨论(0)
  • 2020-11-30 23:15

    As per my comments - because links go dead - I have posted the full code as an answer to the question. YES it is possible to do what the OP is requesting. and here is a nice little gem from Nick demonstrating it. Nick credits this page and another page for his complete solution along with performance metrics. I provide that below instead of just a link.

    // returns property getter
    public static Func<TObject, TProperty> GetPropGetter<TObject, TProperty>(string propertyName)
    {
        ParameterExpression paramExpression = Expression.Parameter(typeof(TObject), "value");
    
        Expression propertyGetterExpression = Expression.Property(paramExpression, propertyName);
    
        Func<TObject, TProperty> result =
            Expression.Lambda<Func<TObject, TProperty>>(propertyGetterExpression, paramExpression).Compile();
    
        return result;
    }
    
    // returns property setter:
    public static Action<TObject, TProperty> GetPropSetter<TObject, TProperty>(string propertyName)
    {            
        ParameterExpression paramExpression = Expression.Parameter(typeof(TObject));
    
        ParameterExpression paramExpression2 = Expression.Parameter(typeof(TProperty), propertyName);
    
        MemberExpression propertyGetterExpression = Expression.Property(paramExpression, propertyName);
    
        Action<TObject, TProperty> result = Expression.Lambda<Action<TObject, TProperty>>
        (
            Expression.Assign(propertyGetterExpression, paramExpression2), paramExpression, paramExpression2
        ).Compile();
    
        return result;
    }
    
    0 讨论(0)
提交回复
热议问题