El lanzamiento implícito no ocurre en el árbol de expresiones

.net c# expression-trees linq type-parameter

Pregunta

Me encontré con un escenario en el que tengo que ordenar una lista de tipos personalizados en diferentes propiedades según la entrada. Con la ayuda de pocos artículos, pude encontrar una implementación genérica utilizando LINQ. Durante la prueba unitaria, una de las pruebas falló porque se estaba produciendo una conversión implícita cuando se creó la expresión lamda usando el árbol de expresiones.

A continuación, coloqué el código de muestra para comprender el problema (no estoy seguro de por qué el formato no fue correcto, perdón por eso)

static class ExtensionMethods
{
 public static IEnumerable<TSource> Sort<TSource>(this IEnumerable<TSource> unSortedList, Func<TSource, object> selector, bool isAscending)
    {
       return isAscending ? unSortedList.OrderBy(selector) :                 unSortedList.OrderByDescending(selector);
}   
}

class Program
{

    class Student
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

    static void Main(string[] args)
    {
        var unOrderedStudents = new List<Student>
                           {
                               new Student{ Name="A", Age=20},
                               new Student{Name = "B", Age=19}
                           };


        //This Works
        var sortUsingLamda = unOrderedStudents.Sort<Student>(stud => stud.Age, true);


        //Exception - Expression of type 'System.Int32' cannot be used for return type 'System.Object'
        var sortUsingExpressionTree = unOrderedStudents.Sort<Student>( GetSortFunc<Student>("Age"), true);

        Console.WriteLine("Press any key to continue");
        Console.ReadLine();
    }



    private static Func<T, object> GetSortFunc<T>(string sortColumn)
    {
        var param = Expression.Parameter(typeof(T), "entity");

        var propertyExpression = Expression.Property(param, sortColumn);

        var boxingExpression = Expression.Convert(propertyExpression, typeof(object));

        return Expression.Lambda<Func<T, object>>(propertyExpression, param).Compile();

        //after adding Convert expression issue got fixed
        //return Expression.Lambda<Func<T, object>>(boxingExpression, param).Compile();

    }
} 

En el método Principal, cuando intento pasar un delegado de Func directamente al método de extensión Ordenar, funciona pero falla con el árbol de Expresión.

Encontré un problema similar , pero se trata de parámetros de tipo restringido. ¿Son ambos los mismos problemas? ¿Puede alguien ayudarme a entender el problema?

Respuesta aceptada

boxingExpression usar la versión en caja (actualmente crea boxingExpression , pero en cambio basa su consulta final en propertyExpression ):

return Expression.Lambda<Func<T, object>>(boxingExpression, param).Compile();

Re por qué esto no está implícita - simplemente no hay conversión implícita aquí; Expression ! = C #. El boxeo es una operación no trivial, y la API de Expression requiere un nodo específico en el árbol.


Respuesta popular

Tiene los prototipos GetSortFunc como devolver una instancia de Func <> que devuelve un objeto. Debido a esto, es su trabajo garantizar que el árbol de expresiones que genere produzca un objeto.

Aunque int se convierte implícitamente en un objeto en C # debajo del capó, se está encajonando. Es por eso que necesita la expresión de boxeo en su código y por qué necesita generar el lambda usando la expresión que obtiene de Expression.Convert . La mejor manera de pensarlo es que al usar árboles de expresiones, debe ser explícito acerca de todas las conversiones y no pensar en cómo escribiría el código C #.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow