2016-07-29 3 views
-1

Juste en essayant quelques bases avec C# Lookup collection et trouvé, que cet exemple simple compiler amende, même IGrouping interface devrait avoir TElement défini comme int.Pourquoi je ne reçois pas d'erreur de syntaxe dans cet exemple de code?

string txt = "Hello world!"; 
ILookup<char, int> occurrences = Enumerable.Range(0, txt.Length).ToLookup(i => txt[i], i => i); 

foreach (IGrouping<char, string> values in occurrences) 
    Console.WriteLine($"{values.Key}: {string.Join(", ", values)}"); 

Évidemment, je reçois une erreur d'exécution sur un cast invalide. Mais je m'y attendais, que ce travail pour le compilateur ...

+0

@PeterDuniho: Peut-on se contenter de [cette question et ces réponses] (http://stackoverflow.com/a/20205068/717732) alors? C'est un littéral. Oui, bien que le ** titre ** soit impair, la question et la sémantique/signification/.. sont les mêmes. – quetzalcoatl

+0

@Quetzalcoatl: beaucoup mieux, oui ... cela semble beaucoup plus comme cette question. Je pense que Scott est allé un peu dans les mauvaises herbes vers la fin de sa réponse avec l'entreprise au sujet de la covariance, mais sinon c'est un fac-similé raisonnable de ce Q & A. –

Répondre

1

Il semble ici est la règle que le compilateur utilise:

Si le compilateur peut voir que le type de valeur ou classe scellée ne pas mettre en œuvre ou hériter du type que le programmeur essaie de lancer , la distribution est illégale à la compilation.

(Merci à Jeppe Nielsen Stig pour mentionner ce dans les commentaires.)

Voici le résultat de la compilation foreach (XXXX values in occurrences) si vous utilisez l'une des options ci-dessous au lieu de XXXX dans votre exemple. Prêtez l'attention occurrences est du type ILookup<char, int> qui est dérivé de IGrouping<char, int>.

  • public class MyClass { } Compile
  • public sealed class MyClass { } Compile Erreur
  • public sealed class MyClass : IGrouping<char, int> {...} Compile
  • public sealed class MyClass : IGrouping<char, string> {...} Compile Erreur d'
  • public struct MyStruct {} Compile Erreur d'
  • public struct MyStruct : IGrouping<char, string> {...} Compile Erreur
  • public struct MyStruct : IGrouping<char, int> {...} Compile

est ici un bon blog post par Krzysztof Cwalina qui décrit comment le typage de canard dans utilisé dans foreach:

opérateur foreach de C# utilise déjà la saisie de canard. Cela peut être surprenant pour certains, mais pour soutenir foreach en C#, vous n'avez pas besoin de mettre en œuvre IEnumerable! Tout ce que vous avez à faire est:

Fournir une méthode publique GetEnumerator qui ne prend aucun paramètre et renvoie un type qui a deux membres: a) une méthode MoveMext sans paramètre et retourner un booléen, et b) une propriété Current avec un getter qui renvoie un objet.

+0

La raison pour laquelle il ne peut pas y avoir d'erreur de compilation, c'est que nous utilisons des interfaces. Le compilateur sait qu'il a un 'IGrouping ' (à partir du type de propriété 'Current'), mais quelle que soit la classe implémente cela, pourrait en principe implémenter aussi' IGrouping '. N'importe qui peut écrire une classe qui implémente les deux.Puisque le compilateur ne peut pas exclure que les éléments réels sont tous comme ça, c'est autorisé. Ma recommandation est d'utiliser 'var' dans toutes les instructions' foreach'. –

+0

@JeppeStigNielsen: _ "pourrait en principe implémenter aussi IGrouping " - mais si la méthode 'GetEnumerator()' appelée n'énumère pas cette interface, cela n'aide pas. La compatibilité d'interface est un hareng rouge complet. _ "Puisque le compilateur ne peut pas exclure ..." - mais, encore une fois ... seulement parce que c'était le choix spécifique des développeurs pour l'instruction 'foreach'. Lorsque les génériques ont été introduits, la spécification aurait pu changer pour exiger une compatibilité de type directe au lieu d'utiliser le dactylographie (pas de conversion vers une interface attendue comme votre commentaire l'indique ... encore une fois, red-hareng). –

+0

@JeppeStigNielsen: _ "Ma recommandation est d'utiliser var dans toutes les déclarations foreach." _ - Pouah, vraiment? Cela annulerait complètement l'utilité de la compatibilité de type pair via le dactylographie, car alors vous devriez écrire vous-même des conversions explicites chaque fois que le type de collection ne correspond pas exactement au type de variable de boucle désiré. –