61 votes

Canard en tapant dans le compilateur C #

Remarque C'est pas une question sur la façon de mettre en œuvre ou à imiter duck-typing en C#...

Pendant plusieurs années j'ai eu l'impression que certaines fonctionnalités de langage C# ont été depdendent sur les structures de données définies dans la langue elle-même (qui m'a toujours semblé étrange de poulet et de l'oeuf scénario pour moi). Par exemple, j'étais sous l'impression que l' foreach boucle était seulement disponible pour une utilisation avec des types qui ont mis en œuvre IEnumerable.

Depuis lors, j'ai fini par comprendre que le compilateur C# utilise le duck-typing pour déterminer si un objet peut être utilisé dans une boucle foreach, la recherche d'un GetEnumerator méthode plutôt que d' IEnumerable. Cela fait beaucoup de sens, car il élimine la poule et de l'oeuf casse-tête.

Je suis un peu confus quant à pourquoi ce n'est pas ne semble pas être le cas avec l' using bloc et IDisposable. Existet-il une raison pour que le compilateur ne peut pas utiliser le duck-typing & pour un look Dispose méthode? Quelle est la raison de cette incohérence?

Peut-être il y a quelque chose d'autre gong sur sous le capot avec IDisposable?

Discuter de pourquoi vous voulez toujours avoir un objet avec une méthode dispose que de ne pas mettre en œuvre IDisposable est en dehors de la portée de cette question :)

39voto

Jon Skeet Points 692016

Il n'y a rien de spécial à propos de IDisposable - mais il est quelque chose de spécial à propos des itérateurs.

Avant de C# 2, l'utilisation de ce type de canard sur foreach a été le seul a vous pourriez mettre en œuvre un typage fort itérateur, et aussi le seul moyen de parcourir des types de valeur sans la boxe. Je soupçonne que si C# et .NET avait génériques pour commencer, foreach aurait exigé IEnumerable<T> au lieu de cela, et pas eu le duck-typing.

Maintenant que le compilateur utilise ce genre de canard en tapant dans un couple de d'autres endroits que je pense:

  • Initialiseurs de la Collection pour un look adapté Add de surcharge (ainsi que le type d'avoir à mettre en oeuvre IEnumerable, juste pour montrer que c'est vraiment une collection de quelque sorte), ce qui permet pour l'ajout flexible des éléments uniques, des paires clé/valeur, etc
  • LINQ (Select etc) - c'est comment LINQ atteint sa flexibilité, permettant à la même expression de requête format à l'encontre de plusieurs types, sans avoir à changer de IEnumerable<T> lui-même
  • Le C# 5 attendent expressions nécessitent GetAwaiter de retour d'un awaiter type qui a IsCompleted / OnCompleted / GetResult

Dans les deux cas, cela rend plus facile d'ajouter de la fonctionnalité à des types existants et des interfaces, où le concept n'existait pas auparavant.

Étant donné qu' IDisposable a été dans le cadre de depuis la toute première version, je ne pense pas qu'il y aurait tout avantage à duck-typing l' using déclaration. Je sais que vous l'avez explicitement essayé de remise raisons pour avoir Dispose sans la mise en œuvre de IDisposable de la discussion, mais je pense que c'est un point crucial. Il doit y avoir de bonnes raisons pour mettre en œuvre une fonction dans la langue, et je dirais que le duck-typing est une fonctionnalité au-dessus et au-delà de l'appui d'une interface connue. Si il n'y a aucun avantage évident en agissant de la sorte, il ne finira pas dans la langue.

12voto

Eamon Nerbonne Points 21663

Il n'y a pas d'oeuf et de la poule: foreach pourrait dépendre IEnumerable depuis IEnumerable ne dépend pas de foreach. La raison foreach est autorisée sur les collections de ne pas mettre en œuvre IEnumerable est probablement en grande partie historique:

En C#, il n'est pas strictement nécessaire pour une collection de classe d'hériter de IEnumerable et IEnumerator dans l'ordre pour être compatible avec foreach; tant comme la classe a les GetEnumerator, MoveNext, Reset, et Les membres actuels, il collaborera avec l' foreach. En omettant les interfaces a l'avantage de vous permettre d' définir le type de retour de Courant être plus précis, l'objet, ce qui fournir le type de sécurité.

De plus, tous poule et de l'œuf problèmes sont en fait des problèmes: par exemple, une fonction peut s'appeler elle-même (récursivité!) ou un type de référence peut contenir lui-même (comme une liste chaînée).

Ainsi, lorsque using est venu autour, pourquoi auraient-ils utiliser quelque chose d'aussi difficile à spécifier que le duck-typing quand ils peuvent simplement dire: mettre en oeuvre IDisposable? Fondamentalement, en utilisant le duck-typing vous êtes en train de faire pour contourner le système de type, qui n'est utile que lorsque le système de type est insuffisant (ou impossible) pour résoudre un problème.

0voto

Gaurav Saxena Points 146

La question que vous demandez n'est pas une poule et de l'œuf. Son plus comme ndique le compilateur de langage est mis en œuvre. Comme C# et VB.NET compilateur sont mis en œuvre différemment.Si vous écrivez un simple code de bonjour tout le monde et de le compiler avec le compilateur et d'inspecter le code IL ils seront différents. Pour revenir à votre question, je tiens à expliquer ce qu'IL code est généré par le compilateur C# pour IEnumerable.

IEnumerator e = arr.GetEnumerator();

while(e.MoveNext())
{
   e.Currrent;
}

Donc le compilateur C# est modifié pour le cas d' foreach.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X