我有一个我希望以这种方式构建的对象:
var foo = new FancyObject(customer, c=>c.Email); //customer has Email property
我应该如何声明第二个参数?
访问所选属性setter / getter的代码如何?
UPD。模型中有多个实体具有Email属性。签名可能看起来像是:
public FancyObject(Entity holder, Expression<Func<T>> selector)
和构造函数调用
var foo = new FancyObject(customer, ()=>customer.Email);
答案 0 :(得分:101)
参数为Expression<Func<Customer,string>> selector
。阅读它可以通过平面编译:
Func<Customer,string> func = selector.Compile();
然后您可以访问func(customer)
。分配比较棘手;对于简单的选择器,你可以希望你可以简单地分解为:
var prop = (PropertyInfo)((MemberExpression)selector.Body).Member;
prop.SetValue(customer, newValue, null);
但更复杂的表达式要么需要手动树遍,要么需要4.0表达式节点类型中的一些:
Expression<Func<Customer, string>> email
= cust => cust.Email;
var newValue = Expression.Parameter(email.Body.Type);
var assign = Expression.Lambda<Action<Customer, string>>(
Expression.Assign(email.Body, newValue),
email.Parameters[0], newValue);
var getter = email.Compile();
var setter = assign.Compile();
答案 1 :(得分:6)
看起来类型必须是通用的两个类型参数 - 源和结果。例如,您可以使用:
var foo = new FancyObject<Customer, string>(customer, c => c.Email);
第一个参数的类型为TSource
,第二个参数为Expression<Func<TSource, TResult>>
:
public class FancyObject<TSource, TResult>
{
private readonly TSource value;
private readonly Expression<Func<TSource, TResult>> projection;
public FancyObject(TSource value,
Expression<Func<TSource, TResult>> projection)
{
this.value = value;
this.projection = projection;
}
}
您可以使用非泛型类型的静态方法更简单:
var foo = FancyObject.Create(customer, c => c.Email);
可以使用类型推断来计算类型参数。