2009-04-08 4 views

ответ

62

Вы не можете просто бросить между ними, так как они не то же самое. Тем не менее, вы можете эффективно добавить преобразование в дерево выражения:

using System; 
using System.Linq.Expressions; 

class Test 
{ 
    // This is the method you want, I think 
    static Expression<Func<TInput,object>> AddBox<TInput, TOutput> 
     (Expression<Func<TInput, TOutput>> expression) 
    { 
     // Add the boxing operation, but get a weakly typed expression 
     Expression converted = Expression.Convert 
      (expression.Body, typeof(object)); 
     // Use Expression.Lambda to get back to strong typing 
     return Expression.Lambda<Func<TInput,object>> 
      (converted, expression.Parameters); 
    } 

    // Just a simple demo 
    static void Main() 
    { 
     Expression<Func<string, DateTime>> x = text => DateTime.Now; 
     var y = AddBox(x);   
     object dt = y.Compile()("hi"); 
     Console.WriteLine(dt); 
    }   
} 
+0

@JonSkeet Expression.Convert не всегда хорошая идея. См. Мой ответ. – Rookian

+0

Это генерирует тот же результат, что и выражение Expression > при объявлении x => x.TodayValue. В результате создается выражение, которое содержит метод «Преобразование()» в теле и выдает некоторые вещи, такие как Linq to Entities. Есть ли способ заставить его работать для такого сценария? Благодарю. – CesarD

+0

@CesarD: Боюсь, это не то, что я пытался сделать, поэтому мне нечего предлагать. –

8

на основе кода от Jon (спасибо кстати) вы можете взять его один шаг для полной гибкости:

public static Expression<Func<TModel, TToProperty>> Cast<TModel, TFromProperty, TToProperty>(Expression<Func<TModel, TFromProperty>> expression) 
{ 
    Expression converted = Expression.Convert(expression.Body, typeof(TToProperty)); 

    return Expression.Lambda<Func<TModel, TToProperty>>(converted, expression.Parameters); 
} 
+0

Есть ли какой-либо пример использования этого? –

23

Ответы от Rob и Jon Skeet есть одна проблема.

Вы получаете что-то вроде x => Convert(x.PropertyName), но часто, например, для ASP.NET MVC вы хотите выражение, как этот x => x.PropertyName

Так Expression.Convert является «загрязняет» выражения для некоторых случаев.

Решение:

public static class LambdaExpressionExtensions 
{ 
    public static Expression<Func<TInput, object>> ToUntypedPropertyExpression<TInput, TOutput> (this Expression<Func<TInput, TOutput>> expression) 
    { 
     var memberName = ((MemberExpression)expression.Body).Member.Name; 

     var param = Expression.Parameter(typeof(TInput)); 
     var field = Expression.Property(param, memberName); 
     return Expression.Lambda<Func<TInput, object>>(field, param); 
    } 
} 

Использование:

Expression<Func<T, DateTime>> expression = ...; 
Expression<Func<T, object>> expr = expression.ToUntypedPropertyExpression(); 
+7

Это не работает. Например, я, похоже, не могу преобразовать 'Int32' в' object'; это то, что для вызова Convert. Без этого я получаю «ArgumentException». Попытка версии «DateTime» - то же самое. Если это сработало для вас, я предполагаю, что вы сделали это со ссылочным типом. –

+0

@rookian вы можете предложить способ использовать свое решение для вложенного свойства? на данный момент он работает как прелесть прямых свойств, но мне нужно получить доступ к вложенным или дочерним свойствам. поэтому, пожалуйста, дайте обновленную версию, если это возможно. благодаря –

0

Просто определить из TResult как объект и составить выражение, оно работает для всех типов данных;

Expression<Func<string, object>> dateExp = text => DateTime.Now; 
object dt = dateExp.Compile()("hi"); 
Console.WriteLine(dt); 

Fiddle sample here

Смежные вопросы