Méthode d'extension et objet dynamique

96

Je vais résumer mon problème dans l'extrait de code suivant.

List<int> list = new List<int>() { 5, 56, 2, 4, 63, 2 };
Console.WriteLine(list.First());

Le code ci-dessus fonctionne correctement.

Maintenant j'ai essayé ce qui suit

dynamic dList = list;
 Console.WriteLine(dList.First());

mais je reçois RuntimeBinderException, pourquoi est-ce le cas?

santosh singh
la source
Cela semble être un double de cette question posée il y a seulement 4 jours stackoverflow.com/questions/5270782/…
jbtule
@jbtule La différence est que le thisest dynamique ici, mais si vous atterrissez ici, vous devriez probablement vous pencher aussi sur cette question
nik.shornikov

Réponses:

131

Pour développer la réponse de Stecya ... les méthodes d'extension ne sont pas supportées par le typage dynamique sous forme de méthodes d'extension , c'est-à-dire appelées comme s'il s'agissait de méthodes d'instance. Cependant, cela fonctionnera:

dynamic dList = list;
Console.WriteLine(Enumerable.First(dList));

Bien sûr, cela peut être utile ou non. Si vous pouviez donner plus d'informations sur les raisons et la manière dont vous essayez d'utiliser la saisie dynamique, nous pourrons peut-être vous aider davantage.

Jon Skeet
la source
Je jouais avec un objet dynamique et j'ai obtenu cette exception.Avez-vous écrit un article sur ce sujet, où utiliser ou non un objet dynamique
santosh singh
19
@geek: Personnellement, ma règle de base est de n'utiliser que dynamiclà où vous en avez vraiment besoin ... fondamentalement, si vous accédiez aux membres avec réflexion, c'est un grand signe. D'un autre côté, je suis un typeur statique irréductible - d'autres peuvent suggérer des politiques moins pessimistes :)
Jon Skeet
2
Il pourrait être plus lisible de renvoyer au type connu, cela fonctionne: Console.WriteLine (((List <int>) dList) .First ()); Ou Console.WriteLine ((dList as List <int>) .First ()) ;.
AVee
138

Pour développer la réponse de Jon, la raison pour laquelle cela ne fonctionne pas est que dans les méthodes d'extension de code standard non dynamiques fonctionnent en effectuant une recherche complète de toutes les classes connues du compilateur pour une classe statique qui a une méthode d'extension qui correspond. La recherche se déroule dans l'ordre en fonction de l'imbrication de l'espace de noms et des usingdirectives disponibles dans chaque espace de noms.

Cela signifie que pour obtenir une résolution correcte d'un appel de méthode d'extension dynamique, le DLR doit savoir au moment de l'exécution quelles usingétaient toutes les imbrications et directives d' espaces de noms dans votre code source . Nous n'avons pas de mécanisme pratique pour encoder toutes ces informations dans le site d'appel. Nous avons envisagé d'inventer un tel mécanisme, mais avons décidé qu'il était trop coûteux et produisait trop de risques de calendrier pour en valoir la peine.

Eric Lippert
la source
Merci beaucoup pour l'éxplication.
santosh singh
3
Une telle fonctionnalité est-elle en vue? Ce serait certainement un changement radical; les appels lancés actuellement par RunTimeBinderExceptions commenceraient soudainement à fonctionner lors de la recompilation de la source. En outre, y aurait-il des risques de sécurité associés à la mise en œuvre d'une telle fonctionnalité?
Ani
5
@ani: Avons -nous l'intention de mettre en œuvre cette fonctionnalité? Non. Existe-t-il des risques de sécurité? Je n'en connais aucun; quel type de risque de sécurité aviez-vous à l'esprit? Commencez par dire qui est l'attaquant et quelle menace il représente pour l'utilisateur.
Eric Lippert
@EricLippert, j'ai compris que tous les dynamicobjets sont égaux à C # :, DynamicObjectil n'y a donc aucun moyen de les différencier et est l'une des raisons pour lesquelles il n'est pas possible d'ajouter des méthodes d'extension dynamic, c'est vrai?
Tom Sarduy
@EricLippert envisage d'élargir un peu plus cette réponse et d'ajouter une phrase du type "Quand l' un des paramètres est dynamique, toutes les résolutions sont différées jusqu'à l'exécution". Bien qu'il soit évident pour vous que cet élément important soit difficile à trouver ailleurs sur SO (voir stackoverflow.com/questions/48324768 par exemple)
Alexei Levenkov
18

Parce que ce First()n'est pas une méthode de List. Il est défini dans l'extension Linq pourIEnumerable<>

Stecya
la source