I've got a LambdaExpression which takes one object as a Parameter and ultimately returns an object. For the purposes of testing, here's a Lambda (created longhand to match what i'm really passing in) that returns a DateTime boxed as an object. For the purposes of working this through, the LambdaExpression takes an XmlNode and returns an object. It must return an object, the real return type could be any of: DateTime,bool,int,decimal,XmlDocument [so far] The general idea is that somewhere deep in a parser, this lambda is created and it extracts a value from it's input parameter and returns it typed, but boxed in an object.
XmlNode node = null;
ParameterExpression instanceExpression = Expression.Parameter(typeof(DynamicNode), "instance");
ParameterExpression result = Expression.Parameter(typeof(object), "result");
LabelTarget blockReturnLabel = Expression.Label(typeof(object));
BlockExpression block = Expression.Block(
typeof(object),
new[] { result },
Expression.Assign(result, Expression.Convert(Expression.Constant(DateTime.Now.AddSeconds(-1)), typeof(object))),
Expression.Return(blockReturnLabel, result),
Expression.Label(blockReturnLabel, Expression.Constant(-2, typeof(object))));
LambdaExpression lax = Expression.Lambda<Func<XmlNode, object>>(block, instanceExpression);
Later in the code, we're evaluating <, <=, >, >=, == and != so we want to compare the result of this LambdaExpression to another Expression
Usually, we can assume the LambdaExpression is on the left of the Expression.LessThan on the right, could be pretty much any expression, but lets assume it's typed. That means that it could be ConstantExpression or similar... but it has a type.
This means that Expression.LessThan [for example] fails because the LambdaExpression when Expression.Invoke is called on it returns an object and the RHS is whatever that type is.
Assuming that the type boxed inside the object returned from the LambdaExpression is actually comparable to the type on the right hand side; e.g.
(object)5 < 6
How do I write an expression that can compare the boxed type to the unboxed type without crashing? I've tried various permutations in linqpad, including trying to write this in normal c#- i.e. no Expressions, just nested if-then-else however I couldn't get that working quite right. Normally, i'd probably write something like this:
/*
int i = 3;
object o = (object)i;
int compare = 4;
*/
DateTime dt = DateTime.Now;
object o = (object)dt;
DateTime compare = DateTime.Now.AddSeconds(1);
bool b = false;
if(o.GetType().IsAssignableFrom(compare.GetType()))
{
if(o is int)
{
b = (int)o < (int)(object)compare;
}
if(o is DateTime)
{
b = (DateTime)o < (DateTime)(object)compare;
}
if(o is decimal)
{
b = (decimal)o < (decimal)(object)compare;
}
}
Console.WriteLine(b);
With this, assuming o and compare are actually the same type and one of them is boxed as an object, we can still perform the < operation...
So I guess my question is, how do I write the above code when I have a LambdaExpression on the left, and Expression on the right [if the two are not the same type, false as a result is better than a crash]
Hope someone can help,
Gareth
You can use the
Expression.Unbox
method for this: "Creates a UnaryExpression that represents an explicit unboxing."Let's take your
(int)(object)5 < 6
example:In this case, you can write a conditional-expression that checks if the run-time type of the boxed-object is the same as the type of the right-hand side, and do the unboxing + less-than comparison if they are, or just return false otherwise.
E.g.