user553671
user553671

Reputation:

C# Expression Tree: Using TypeAs

My first foray into writing an expression tree in c# is not going too well :). Here's the c# code I'm trying to duplicate

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;
}

Conceptually, this is intended to take an object and apply a selector to it to return a property of a derived class if the supplied object is of the derived class.

Here's what I've got so far:

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);
}

I've used a somewhat different set of arguments here to simplify my expressions.

The code works when derivedType is, in fact, a Type derived from S. However, if it isn't -- when I'm expecting the code to return retVal = null -- it blows up at the following line:

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

complaining that fieldName is not a property of varDest. Which is correct in that case...but I was expecting the "if true" arm of the Condtional expression to not be evaluated if the test expression was false. That's clearly not the case.

What I don't know about expression trees would fill (more than) a book. But if someone can point out where I'm going off the rails I'd appreciate it.

Upvotes: 0

Views: 1245

Answers (1)

Double Down
Double Down

Reputation: 908

Not sure if you ever got this answered but here's what you need

        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);
        }

Upvotes: 1

Related Questions