【问题标题】:How to set a property value from an expression tree?如何从表达式树中设置属性值?
【发布时间】:2019-09-11 17:16:02
【问题描述】:

我想设置表达式树中引用的属性值。

using System;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;

namespace ConsoleApp8
{
    class TestObject
    {
        public double X { get; set; }
    }

    class Program
    {
        static Action<double> GetSetterForX(Expression<Func<double>> expression)
        {
            var body = expression.Body;
            var operand = body as MemberExpression;
            var propertyInfo = (PropertyInfo) (operand.Member);
            var setter = propertyInfo.GetSetMethod(true);

            // At this point I have the setter. But how do I get access to the testObject?

            return null;
        }

        static void Main(string[] args)
        {
            var testObject = new TestObject();
            var setter = GetSetterForX(() => testObject.X);
            setter.Invoke(5);
            Debug.Assert(testObject.X == 5);
        }
    }
}

我可以获取 setter,但找不到访问实例 (testObject) 的方法。有什么办法吗?

请注意,这是一个简化的示例。我将使用更复杂的表达式,其中包含许多属性引用,并且我希望能够(单独)设置所有这些表达式。

更新

澄清一下。我想返回一个只需要一个双精度的 setter,它分配 testObject 的 X 属性。这应该是可能的,无需在 setter 中显式传入对 testObject 的引用。 我可以做同样的事情来获得吸气剂,但不能用于二传手。这是getter代码:

static Func<double> GetGetterForX(Expression<Func<double>> expression)
{
    var body = expression.Body;
    var operand = body as MemberExpression;
    var result = new Func<double>(() => (double) GetValue(operand));

    return result;
}

private static object GetValue(MemberExpression member)
{
    var objectMember = Expression.Convert(member, typeof(object));
    var getterLambda = Expression.Lambda<Func<object>>(objectMember);
    var getter = getterLambda.Compile();
    return getter();
}

返回的 getter 总是在 testObject 实例上工作。无需再次传入testObject。

【问题讨论】:

    标签: c# .net expression-trees


    【解决方案1】:

    只要输入的 lambda 表达式表示成员访问器,您就可以使用 Expression.Assign 传递输入的 lambda 表达式主体和表示值的参数,例如

    static Action<double> GetSetterForX(Expression<Func<double>> expression)
    {
        var parameter = Expression.Parameter(typeof(double), "value");
        var body = Expression.Assign(expression.Body, parameter);
        var lambda = Expression.Lambda<Action<double>>(body, parameter);
        return lambda.Compile();
    }
    

    【讨论】:

      【解决方案2】:

      您需要返回MethodInfo 而不是Action&lt;double&gt;Invoke(object obj, object[] params) 也需要原始对象和参数:

      static MethodInfo GetSetterForX(Expression<Func<double>> expression)
      {
          var body = expression.Body;
          var operand = body as MemberExpression;
          var propertyInfo = (PropertyInfo)(operand.Member);
          var setter = propertyInfo.GetSetMethod(true);
          return setter;
      }
      
      public static void Main()
      {
          var testObject = new TestObject();
          var setter = GetSetterForX(() => testObject.X);
          setter.Invoke(testObject, new object[]{5});
          Debug.Assert(testObject.X == 5);
      }
      

      小提琴:https://dotnetfiddle.net/CHJGbk

      【讨论】:

      • 这不是我想要的。我希望能够通过提供 () =&gt; testObject.X 表达式从 testobject 中获取 X 的值。我相信这应该是可能的,我可以写一个GetGetter。我会更新问题
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-24
      • 2010-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多