Get actual return type from a Expression<Func<T, object>> instance

c# expression-trees reflection

Question

I have a method that accepts a Expression<Func<T, object>> instance. I want to get at the actual data type being returned by a specific expression instance, rather than object.

I can get it to work for direct property references, so if I pass in the expression x => x.IntegerProperty I can get a Type reference for an integer. This approach requires converting it to a MemberExpression.

However, I can't get it to work for arbitrary expressions. For instance, if the expression is x => x.IntegerProperty.ToString() I want to get a Type reference for a string. I can't compile this to a MemberExpression, and if I just .Compile() it and check the return type I get "object".

How can I look at the specific expression instance and derive the actual return type?

Accepted Answer

Something like this might do the trick. It probably doesn't cover every possibility, but it's a start.

public static Type GetObjectType<T>(Expression<Func<T, object>> expr)
{
    if ((expr.Body.NodeType == ExpressionType.Convert) ||
        (expr.Body.NodeType == ExpressionType.ConvertChecked))
    {
        var unary = expr.Body as UnaryExpression;
        if (unary != null)
            return unary.Operand.Type;
    }
    return expr.Body.Type;
}

Popular Answer

While not impossible, this is particularly difficult. It would require walking the expression tree and doing some potentially complex logic. For example, what would you want to see if I passed in the following expression?

Func<bool, object> expr = switch => switch ? 1 : "False";

This method could either return an int or a string.

Now, you might be able to make more headway by offloading some of this logic on the compiler. You could change your method parameter from Func<T, object> to Func<T, TReturn> and use typeof(TReturn) within the method to determine what the compiler decided the return type of the expression was.

Of course, in the case of my example, you'll still be working against object. But, your example of x => x.IntegerProperty.ToString() will yield string, which is what you're looking for.




Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why