Как преобразовать выражение < Действие < T, object > > > к выражению < Действие < T, U > & gt ;?

l33t спросил: 28 апреля 2018 в 09:23 в: c#

У меня есть выражение, которое принимает параметр типа object. Мне нужно создать типизированное выражение во время выполнения с помощью переменной Type. Смотри ниже. Параметр должен иметь тип int, поэтому я получаю код Expression<Action<Program, int>>, который для данного int вызывает непечатаемый Set метод. Как это можно сделать?

class Program
{
    private static Type SomeRuntimeType() => typeof(int);    public void Set(object v)
    {
        Debug.WriteLine("Setting value...");
    }    static void Main(string[] args)
    {
        Expression<Action<Program, object>> e1 = (t, v) => t.Set(v);        var type = SomeRuntimeType();
        // TODO: Create typed expression...
        Expression<Action<Program, type>> e2 = ...
    }
}

1 ответ

Есть решение
xanatos ответил: 28 апреля 2018 в 09:47

Простое решение: с точки зрения C # выражение Lambda Expression является нетипизированным (оно имеет тип LambdaExpression). Во время выполнения он имеет "правильный тип" (например, Expression<Action<Program, T2>>), это возможно, потому что Expression<T> подклассы LambdaExpression)

Expression<Action<Program, object>> e1 = (t, v) => t.Set(v);var type = typeof(int);
var par1 = e1.Parameters[0];
var par2 = Expression.Parameter(type);// if type is a value type, you have to expressly box it 
Expression conv = type.IsValueType ? (Expression)Expression.Convert(par2, typeof(object)) : par2;// We "chain" the two expressions
InvocationExpression invoke = Expression.Invoke(e1, par1, conv);
LambdaExpression lambda = Expression.Lambda(invoke, par1, par2);var compiled = lambda.Compile();// sanity check, 
bool lambdaTypeIsExpected = typeof(Expression<>).MakeGenericType(typeof(Action<,>).MakeGenericType(typeof(Program), type)) == lambda.GetType();

Обратите внимание, что если вам нужен код LambdaExpression для некоторой ORM или какой-либо другой подсистемы, не все библиотеки поддерживают Invoke (которые могут быть удалены с помощью редиректора выражения) или Convert (что необходимо для преобразования из типа значения в тип ссылки). Я даже видел библиотеки, которым не нравится object full-stop (я уже много раз пробовал эти трюки :-))

l33t ответил: 28 апреля 2018 в 09:56
Работает как шарм. Спасибо!