您当然可以遍历表达式树,然后使用Delegate.CreateDelegate 创建适当的Action<,>。这很简单,除了所有的验证检查(我不确定我是否已经涵盖了所有内容):
我不是表达式树专家,但我不认为构建表达式树然后在这里调用 Compile 是可能的,因为表达式树不能包含据我所知,赋值语句。(编辑:显然,这些已添加到 .NET 4 中。这是一个很难找到的功能,因为 C# 编译器似乎没有能够从 lambda 构建它们)。
public static Action<TContaining, TProperty>
CreateSetter<TContaining, TProperty>
(Expression<Func<TContaining, TProperty>> getter)
{
if (getter == null)
throw new ArgumentNullException("getter");
var memberEx = getter.Body as MemberExpression;
if (memberEx == null)
throw new ArgumentException("Body is not a member-expression.");
var property = memberEx.Member as PropertyInfo;
if (property == null)
throw new ArgumentException("Member is not a property.");
if(!property.CanWrite)
throw new ArgumentException("Property is not writable.");
return (Action<TContaining, TProperty>)
Delegate.CreateDelegate(typeof(Action<TContaining, TProperty>),
property.GetSetMethod());
}
用法:
public class Person { public int Age { get; set; } }
...
static void Main(string[] args)
{
var setter = CreateSetter((Person p) => p.Age);
var person = new Person();
setter(person, 25);
Console.WriteLine(person.Age); // 25
}
请注意,这会创建一个 open 实例委托,这意味着它不会绑定到 TContaining 的任何特定实例。将其修改为绑定到 特定的 实例很简单;您还必须将TContaining 传递给该方法,然后使用Delegate.CreateDelegate 的不同重载。该方法的签名将类似于:
public static Action<TProperty> CreateSetter<TContaining, TProperty>
(Expression<Func<TContaining, TProperty>> getter, TContaining obj)