Получить фактический тип возврата из выражения> экземпляр - PullRequest
12 голосов
/ 08 ноября 2011

У меня есть метод, который принимает экземпляр Expression<Func<T, object>>.Я хочу получить фактический тип данных, возвращаемый конкретным экземпляром выражения, а не object.

. Я могу заставить его работать для прямых ссылок на свойства, поэтому, если я передамв выражении x => x.IntegerProperty я могу получить ссылку на тип для целого числа.Этот подход требует преобразования его в MemberExpression.

Однако я не могу заставить его работать для произвольных выражений.Например, если выражение x => x.IntegerProperty.ToString(), я хочу получить ссылку на тип для строки.Я не могу скомпилировать это в MemberExpression, и если я просто .Compile() проверю тип возвращаемого значения и получу «object».

Как я могу посмотреть на конкретный экземпляр выражения и получить фактический тип возвращаемого значения

Ответы [ 3 ]

23 голосов
/ 08 ноября 2011

Нечто подобное может сработать.Это, вероятно, не охватывает все возможности, но это начало.

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;
}
2 голосов
/ 08 ноября 2011

Хотя это не невозможно, это особенно сложно.Это потребует обхода дерева выражений и выполнения некоторой потенциально сложной логики.Например, что бы вы хотели увидеть, если бы я передал следующее выражение?

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

Этот метод может либо вернуть int, либо string.

Теперь вы могли бы добиться большего, разгружая часть этой логики в компиляторе.Вы можете изменить параметр вашего метода с Func<T, object> на Func<T, TReturn> и использовать typeof(TReturn) в методе, чтобы определить, что компилятор решил, что тип возвращаемого значения выражения был.

Конечно, в случае моегоНапример, вы все равно будете работать против object.Но ваш пример x => x.IntegerProperty.ToString() даст string, и это то, что вы ищете.

0 голосов
/ 08 ноября 2011

Немного дерзкого пути (и это включает в себя на самом деле вызов 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.Но это, по крайней мере, потенциальная отправная точка.

...