La diffusion implicite ne se produit pas dans l'arbre d'expression

.net c# expression-trees linq type-parameter

Question

Je suis tombé sur un scénario dans lequel je devais trier une liste de types personnalisés sur différentes propriétés en fonction des entrées. À l'aide de quelques articles, j'ai été en mesure de proposer une implémentation générique à l'aide des tests unitaires LINQ.During. L'un des tests a échoué car une conversion implicite se produisait lors de la création d'une expression lamda à l'aide de l'arbre d'expression.

Ci-dessous, j'ai mis l'exemple de code pour comprendre le problème (Vous ne savez pas pourquoi le formatage n'a pas été correct, désolé pour cela)

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

    }
} 

Dans la méthode Main, lorsque j'essaie de passer un délégué Func directement à la méthode d'extension Sort, cela fonctionne mais cela échoue avec l'arborescence Expression.

J'ai trouvé un problème similaire , mais qui parle de paramètres de type contraint. Les deux problèmes sont-ils les mêmes? Quelqu'un peut-il m'aider à comprendre le problème?

Réponse acceptée

Vous devez utiliser la version boxed (vous créez actuellement boxingExpression , mais boxingExpression votre requête finale sur propertyExpression ):

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

Re pourquoi ce n'est pas implicite - il n'y a tout simplement pas coulée implicite ici; Expression ! = C #. La boxe est une opération non triviale et l'API d' Expression requiert un nœud spécifique dans l'arborescence.


Réponse populaire

Vous avez des prototypes GetSortFunc comme renvoyant une instance Func <> qui renvoie un objet. C'est pourquoi votre travail consiste à vous assurer que l'arborescence d'expression que vous générez génère un objet.

Bien que int dans convertisse implicitement en un objet en C # sous le capot, il est mis en boîte. C'est pourquoi vous avez besoin de l'expression de boxe dans votre code et de générer le lambda à l'aide de l'expression que vous récupérez de Expression.Convert . La meilleure façon de penser à cela est que lorsque vous utilisez des arbres d'expression, vous devez être explicite à propos de toutes les conversions et ne pas y penser en termes d'écriture du code C #.



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi