C#表达式树:使用TypeAs

时间:2012-07-18 00:38:35

标签: expression-trees

我在c#中编写表达式树的第一次尝试并不太顺利:)。这是我试图复制的c#代码

public static object Test<S, D>(S source, Func<D, object> selector )
    where S : class
    where D : class
{
    D derived = source as D;

    object retVal = null;

    if( derived != null ) retVal = selector(derived);

    return retVal;
}

从概念上讲,这是为了获取一个对象并对其应用一个选择器,以便在所提供的对象属于派生类时返回派生类的属性。

这是我到目前为止所得到的:

public static object OrderByDerivedProperty<S>( S source, Type derivedType, string fieldName )
{
    ParameterExpression parameter = Expression.Parameter(typeof(S), "source");
    UnaryExpression typeAs = Expression.TypeAs(parameter, derivedType);

    ConstantExpression nullConst = Expression.Constant(null);
    BinaryExpression isNotNull = Expression.NotEqual(typeAs, nullConst);

    ParameterExpression varDest = Expression.Variable(derivedType, "varDest");
    ParameterExpression retVal = Expression.Variable(typeof(object), "retVal");

    BlockExpression block = Expression.Block(
        new[] { varDest, retVal },
        Expression.Assign(varDest, typeAs),
        Expression.Condition(
            isNotNull, 
            Expression.Assign(retVal, Expression.Property(varDest, fieldName)), 
            Expression.Assign(retVal, nullConst)
            ),
        retVal
    );

    LambdaExpression lambda = Expression.Lambda(block, new[] { parameter });

    return lambda.Compile().DynamicInvoke(source);
}

我在这里使用了一些不同的参数来简化我的表达式。

当derivedType实际上是从S派生的Type时,代码可以工作。但是,如果不是 - 当我期望代码返回retVal = null时 - 它会在以下行中爆炸:

Expression.Assign(retVal, Expression.Property(varDest, fieldName)), 

抱怨fieldName不是varDest的属性。在这种情况下哪个是正确的......但是我期待如果测试表达式为假,则不会评估Condtional表达式的“if true”组。事实显然并非如此。

我不知道表达树会填满(超过)一本书。但如果有人能指出我要离开的地方,我会很感激。

1 个答案:

答案 0 :(得分:0)

不确定你是否得到了这个答案,但这就是你需要的

        public static object OrderByDerivedProperty<TSource>(TSource source, Type derivedType, string propertyOrFieldName)
        {
            if (!derivedType.IsClass)
            {
                throw new Exception("Derived type must be a class.");
            }
            ParameterExpression sourceParameter = Expression.Parameter(typeof(object), "source");
            ParameterExpression typeAsVariable = Expression.Variable(derivedType);
            ParameterExpression returnVariable = Expression.Variable(typeof(object));
            BlockExpression block = Expression.Block(
                new[] { typeAsVariable,returnVariable },
                Expression.Assign(
                    typeAsVariable, 
                    Expression.TypeAs(
                        sourceParameter,
                        derivedType
                    )
                ),
                Expression.Condition(
                    Expression.NotEqual(
                        typeAsVariable,
                        Expression.Constant(
                            null, 
                            derivedType
                        )
                    ),
                    Expression.Assign(
                        returnVariable, 
                        Expression.Convert(
                            Expression.PropertyOrField(
                                typeAsVariable, 
                                propertyOrFieldName
                            ),
                            typeof(object)
                        )
                    ),
                    Expression.Assign(
                        returnVariable, 
                        Expression.Constant(
                            null,
                            typeof(object)
                        )
                    )
                ),
                returnVariable
            );
            var lambda = Expression.Lambda<Func<object,object>>(block, new[] { sourceParameter });
            return lambda.Compile().Invoke(source);
        }