属性选择器Expression <Func <T >>.如何获取/设置所选属性的值

v00*_*d00 64 c#

我有一个对象,我想以这种方式构造:

var foo = new FancyObject(customer, c=>c.Email); //customer has Email property
Run Code Online (Sandbox Code Playgroud)

我该如何申报第二个参数?

访问所选属性setter/getter的代码如何?

UPD.模型中有多个实体具有Email属性.所以签名可能看起来像:

public FancyObject(Entity holder, Expression<Func<T>> selector)
Run Code Online (Sandbox Code Playgroud)

和构造函数调用

var foo = new FancyObject(customer, ()=>customer.Email);
Run Code Online (Sandbox Code Playgroud)

Mar*_*ell 104

参数将是一个Expression<Func<Customer,string>> selector.阅读它可以通过平面编译:

 Func<Customer,string> func = selector.Compile();
Run Code Online (Sandbox Code Playgroud)

然后你就可以访问了func(customer).分配比较棘手; 对于简单的选择器,您可以希望您可以简单地分解为:

var prop = (PropertyInfo)((MemberExpression)selector.Body).Member;
prop.SetValue(customer, newValue, null);
Run Code Online (Sandbox Code Playgroud)

但是更复杂的表达式要么需要手动树遍,要么需要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();
Run Code Online (Sandbox Code Playgroud)

  • @Neo不,这不是“更正确”——它只是“不太直接”;抱歉,但我非常了解 `Expression` API。我可以满足于“email.Parameters.Single()”,但是:上面的版本很好。 (2认同)

Jon*_*eet 6

看起来类型必须是通用的两个类型参数 - 源和结果.例如,您可以使用:

var foo = new FancyObject<Customer, string>(customer, c => c.Email);
Run Code Online (Sandbox Code Playgroud)

第一个参数是类型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;
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以使用非泛型类型中的静态方法更简单:

var foo = FancyObject.Create(customer, c => c.Email);
Run Code Online (Sandbox Code Playgroud)

这可以使用类型推断来计算类型参数.