Pourquoi l&#39;utilisation de .Select () de Linq renvoie IEnumerable <dynamic> même si le type est clairement défini?

casting dapper dynamic linq

Question

J'utilise Dapper pour renvoyer des objets dynamiques et parfois les mapper manuellement. Tout fonctionne très bien, mais je me demandais quelles étaient les lois du casting et pourquoi les exemples suivants étaient vrais.

(pour ces exemples, j'ai utilisé "StringBuilder" comme type connu, bien qu'il s'agisse généralement de "Produit")

Example1: Pourquoi cela retourne-t-il un IEnumerable<dynamic> même si 'makeStringBuilder' renvoie clairement un objet StringBuilder ?

Example2: Pourquoi est-ce que cela se construit, mais 'Example1' ne serait pas si c'était IEnumerable<StringBuilder> ?

Example3: Même question que Example2?

private void test()
    {
        List<dynamic> dynamicObjects = {Some list of dynamic objects};

        IEnumerable<dynamic> example1 = dynamicObjects.Select(s => makeStringBuilder(s));

        IEnumerable<StringBuilder> example2 = dynamicObjects.Select(s => (StringBuilder)makeStringBuilder(s));

        IEnumerable<StringBuilder> example3 = dynamicObjects.Select(s => makeStringBuilder(s)).Cast<StringBuilder>();

    }

    private StringBuilder makeStringBuilder(dynamic s)
    {
        return new StringBuilder(s);
    }

Avec les exemples ci-dessus, existe-t-il un moyen recommandé de gérer cela? et est-ce que le casting comme ça nuit à la performance? Merci!

Réponse acceptée

Lorsque vous utilisez la dynamic , même en tant que paramètre, l'expression entière est gérée via la liaison dynamique et se traduira par une "dynamique" au moment de la compilation (car elle est basée sur son type d'exécution). Ceci est couvert dans 7.2.2 de la spécification C #:

Cependant, si une expression est une expression dynamique (c’est-à-dire de type dynamique), cela signifie que toute liaison à laquelle elle participe doit être basée sur son type d’exécution (c’est-à-dire le type de l’objet que le type qu'il a au moment de la compilation. La liaison d'une telle opération est donc différée jusqu'au moment où l'opération doit être exécutée pendant l'exécution du programme. Ceci est appelé liaison dynamique.

Dans votre cas, l'utilisation de la distribution convertira en toute sécurité en IEnumerable<StringBuilder> et aura très peu d'impact sur les performances. La version example2 est très légèrement plus efficace que la version example3 , mais les deux ont très peu de charge lorsqu'ils sont utilisés de cette manière.


Réponse populaire

Bien que je ne puisse pas très bien parler du "pourquoi", je pense que vous devriez pouvoir écrire example1 comme:

IEnumerable<StringBuilder> example1 = dynamicObjects.Select<dynamic, StringBuilder>(s => makeStringBuilder(s));

Vous devez indiquer au compilateur le type que doit prendre la projection, même si je suis sûr que quelqu'un d'autre peut expliquer pourquoi il ne peut pas déduire le type correct. Mais je pense qu'en spécifiant le type de projection, vous pouvez éviter d'avoir à lancer réellement, ce qui devrait générer des avantages en termes de performances.




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