从Expression <func <t,object =“”>&gt;获取实际的返回类型实例</FUNC <t时,>

时间:2011-11-08 18:05:35

标签: c# reflection expression-trees

我有一个接受Expression<Func<T, object>>实例的方法。我希望得到特定表达式实例返回的实际数据类型,而不是object

我可以让它用于直接属性引用,所以如果我传入表达式x => x.IntegerProperty,我可以得到一个整数的Type引用。这种方法需要将其转换为MemberExpression。

但是,我不能让它适用于任意表达式。例如,如果表达式为x => x.IntegerProperty.ToString(),我想获得字符串的Type引用。我无法将其编译为MemberExpression,如果我只是.Compile()并检查返回类型,我会得到“对象”。

如何查看特定的表达式实例并派生实际的返回类型?

3 个答案:

答案 0 :(得分:22)

这样的事情可能会成功。它可能并未涵盖所有可能性,但它是一个开始。

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

答案 1 :(得分:2)

虽然并非不可能,但这一点特别困难。它需要遍历表达式树并执行一些可能复杂的逻辑。例如,如果我传入以下表达式,您希望看到什么?

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

此方法可以返回intstring

现在,您可以通过在编译器上卸载一些逻辑来取得更多进展。您可以将方法参数从Func<T, object>更改为Func<T, TReturn>,并在方法中使用typeof(TReturn)来确定编译器决定表达式返回类型的内容。

当然,就我的例子而言,你仍然会反对object。但是,x => x.IntegerProperty.ToString()的示例会产生string,这正是您所寻找的。

答案 2 :(得分:0)

一种厚颜无耻的方式(它涉及实际调用Func),但你可以这样做:

using System;

class Program
{
    static Func<T,object> MakeFunc<T>()
    {
        return x => 23;
    }

    static Type GetReturnType<T>(Func<T,object> f)
    {
        return f(default(T)).GetType();
    }

    static void Main(string[] args)
    {
        Type t = GetReturnType(MakeFunc<string>());
        Console.WriteLine(t);
    }
}

不保证在所有情况下均可使用,我应该添加 - 特别是如果default(T)不是Func的有效参数。但这至少是一个潜在的起点。