Reputation:
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
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