0

我第一次尝试在 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 的属性。在那种情况下这是正确的......但如果测试表达式为假,我期望条件表达式的“如果为真”臂不会被评估。显然不是这样。

我对表达式树的不了解会填满(超过)一本书。但是,如果有人能指出我要在哪里出轨,我将不胜感激。

4

1 回答 1

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);
        }
于 2013-07-15T16:54:18.753 回答