2009-04-08 17 views

Respuesta

62

No se puede echar entre ellos, ya que no son el mismo tipo de cosas; Sin embargo, se puede añadir de manera efectiva una conversión dentro del árbol de expresión:

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 no es siempre una buena idea. Ver mi respuesta – Rookian

8

Basado en el código de Jon (gracias por cierto) que puede llevarlo un paso más allá de la flexibilidad completa:

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

¿Hay algún ejemplo de uso de esto? –

23

Las respuestas desde Rob y Jon Skeet tienen un problema.

se obtiene algo como x => Convert(x.PropertyName), pero a menudo, por ejemplo, para ASP.NET MVC que desea una expresión como esta x => x.PropertyName

Así Expression.Convert es "contaminante" la expresión de algunos casos.

Solución:

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

Uso:

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

Esto no parece funcionar. Por ejemplo, parece que no puedo convertir 'Int32' a' object'; para eso es la llamada 'Convert'. Sin él, obtengo una 'ArgumentException'. Probando la versión 'DateTime', lo mismo. Si esto funcionó para ti, supongo que lo hiciste con un tipo de referencia. –

0

Sólo definen el cabo TResult como objeto y compilar la expresión, funciona para todos los tipos de datos;

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

Fiddle sample here

Cuestiones relacionadas