Вызов Func‹› с аргументом типа object

У меня есть (например) Func<int, int>, который я хочу вызывать как обычно, за исключением того, что параметр имеет тип object, а не int. Я знаю только точный тип Func и аргумент во время выполнения, потому что Func был создан с использованием деревьев выражений и теперь доступен из переменной dynamic. (Упрощенный) пример кода:

using System.Linq.Expressions;

namespace FuncExample
{
    class Program
    {
        static void Main(string[] args)
        {
            object myFunc = CreateFunc(); // Could return something like
                                          // Func<int, int>, but may return a
                                          // completely different Func<> depending on
                                          // arguments etc.
            object result = getFromFunc(5, myFunc);
        }

        public static object CreateFunc()
        {
            LambdaExpression expr = Expression.Lambda(
                /*
                 * Create an expression
                 */
                );
            return expr.Compile();
        }

        public static object getFromFunc(object arg, object func)
        {
            dynamic dynFunc = func;
            return dynFunc(arg); // <------- Throws exception
        }
    }
}

Как я могу заставить код преобразовать arg в целое число или любой другой тип аргумента? Я попытался создать общий метод, который приводит объект к определенному типу, а затем вызывает его через отражение следующим образом:

public static T asT<T>(object n)
{
    return (T)n;
}

для getFromFunc:

MethodInfo con = typeof(Program).GetMethod("asT").MakeGenericMethod(func.GetType().GetGenericArguments()[0]);
return dfunc(con.Invoke(null, new[] { value }));

Но MethodInfo.Invoke также возвращает object. Любые идеи о том, как убедиться, что аргумент имеет правильный тип?


person Community    schedule 09.05.2013    source источник
comment
какое исключение выдает?   -  person Charles Lambert    schedule 09.05.2013
comment
@CharlesLambert В моей системе я получаю, что у делегата «System.Func‹int,int›» есть недопустимые аргументы. Он использует статический тип arg, object, который не подходит для функции с параметром типа int.   -  person    schedule 09.05.2013


Ответы (3)


Вы уже используете dynamic, так почему бы не использовать dynamic?

return dynFunc((dynamic)arg);

Это гарантирует, что тип среды выполнения arg используется для определения того, является ли он подходящим аргументом.

person Community    schedule 09.05.2013
comment
Является ли if (!(func.GetType().GetGenericArguments()[0] == arg.GetType())) допустимым способом проверить, является ли это неправильным типом? - person ; 09.05.2013
comment
@MarkusHimmel Это вызовет исключение, если arg равно null, и не будет выполнять никаких неявных преобразований, что приведет к ложному отрицательному результату, если, например, функция принимает интерфейс или базовый класс, а аргумент является производным классом. Я думаю, вам лучше не проверять заранее: вы можете надежно поймать исключение и сделать что-то значимое, если среда выполнения обнаружит, что аргумент имеет неправильный тип. - person ; 09.05.2013

Все делегаты являются производными от System.Delegate. Вы можете использовать метод System.Delegate.DynamicInvoke для вызова делегата, тип которого вам неизвестен во время компиляции, аналогично вызову метода с помощью MethodInfo.Invoke(). Например:

class Program
{
    public static Delegate CreateFunc()
    {
      return new Func<int, int>(x => x + 1);
    }

    public static void Main(string[] args)
    {
        var func = CreateFunc();
        object inArg = 42;
        object result = func.DynamicInvoke(inArg);
        Console.WriteLine(result);
    }
}
person Adam Jenkins    schedule 09.05.2013

Как насчет чего-то подобного?

public static int Main(string[] args)
{
    // this could be any other lambda expression
    Func<object, object> unknownFunc = (a) => { return 13; };

    int result = (int) unknownFunc(13);
    Console.WriteLine(result);

    return 0;
}
person dinony    schedule 09.05.2013
comment
Это не работает, потому что во время компиляции я не знаю, будет ли это int или любой другой тип. - person ; 10.05.2013