将Expression应用于Expression中的object属性

时间:2014-05-29 19:22:26

标签: linq expression

我有一个属性为另一个类的类。我还有一个表达式,可以映射其他类。如何在不编译第二个表达式的情况下将这两个表达式组合成一个表达式?

public class ClassA
{
    public int SomeProperty { get; set; }
}

public class MappedClassA
{
    public int MappedProperty { get; set; }
}

public class ClassB
{
    public ClassA ClassAProperty { get; set; }
    //snip...
}

public class MappedClassB
{
    public MappedClassA  MappedClassAProperty {get; set; }
}

public Expression<Func<ClassA, MappedClassA>> MapAExpression()

{
    return a => new MappedClassA()
    {
        MappedProperty = a.SomeProperty
    };
}

public Expression<Func<ClassB, MappedClassB>> MapBExpression()
{
    return b => new MappedClassB()
    {
        //this should be done with the above expression
        MappedClassAProperty = new MappedClassA()
        {
                MappedProperty = b.ClassAProperty.SomeProperty
        }
    };
}

1 个答案:

答案 0 :(得分:2)

这可以不编译表达式,但遗憾的是不能使用简单的lambda语法来构造表达式。

您必须使用expression methodsExpression.New()Expression.Lambda()手动创建表达式树#34;

这很快就会变得难以理解。

我尝试从下面的记忆中组装这样的表达,但我缺乏练习;这是未经测试的,可能还有一些漏洞。

public Expression<Func<ClassB, MappedClassB>> MapBExpression()
{
    // generate a parameter of type ClassB. 
    // This is the parameter "b" our final lambda expression will accept.
    var classBparam = Expression.Parameter(typeof(ClassB)); 

    // access b.ClassAProperty; this is the property 
    // that we want to pass to the expression returned by MapAExpression() 
    var memberAccess = Expression.MakeMemberAccess(
                          classBparam, 
                          typeof(ClassB).GetProperty("ClassAProperty"));

     // invoke the lambda returned by MapAExpression() 
     //with the parameter b.ClassAProperty 
     var invocation  = Expression.Invoke( MapAExpression(), memberAccess );

     // create a new MappedClassB(), this is the object that will be returned
     // by the expression we are currently creating
     var ctor = Expression.New(typeof(MappedClassB));

     // We want to assign something to the MappedClassB.MappedClassAProperty
     var mappedClassAProperty = 
           typeof(MappedClassB).GetProperty("MappedClassAProperty");

    // specifically, we want to assign the result of our MapAExpression(), 
    // when invoked with the parameter b.ClassAProperty
    var mappedClassAAssignment = 
           Expression.Bind(mappedClassAProperty, invocation);

    // Here we initialize the MappedClassAProperty, 
    // after creating the new MappedClassB.
    // We initialize it with the assignment we just created
    var memberInit = Expression.MemberInit(ctor, mappedClassAAssignment);

    // finally, we construct the lambda 
    //that does all of the above, given a parameter of type ClassB
    return Expression.Lambda<Func<ClassB, MappedClassB>>(memberInit, classBparam);

    // this expression should now be equivalent to:
    // return b => new MappedClassB()
    // {
        // MappedClassAProperty = new MappedClassA()
        // {
            // MappedProperty = b.ClassAProperty.SomeProperty
        // }
    // };

}