Mise à JOUR: Cette question a été l'objet de mon blog en juillet 2013. Merci pour la grande question!
Pourquoi est-ce foreach pas créer la même erreur que l'affectation de variable n'?
Le "pourquoi" des questions difficiles à répondre car je ne sais pas la "vraie" question posée. Ainsi, au lieu de répondre à la question, je vais répondre à certaines questions.
Ce que la section de la spécification justifie ce comportement?
Comme Michael Liu, en réponse à juste titre, il est de la section 8.8.4.
Le point de l'ensemble d'un explicite de conversion, c'est que la conversion doit être explicite dans le code; c'est pourquoi nous avons l'opérateur de cast; c'est en agitant un grand drapeau qui dit "il y en a une conversion explicite ici". C'est l'une des rares fois dans C#, où une conversion explicite n'existe pas dans le code. Quels sont les facteurs qui ont motivé l'équipe de conception de manière invisible, insérer "explicite" de la conversion?
L' foreach
boucle a été conçu avant l'arrivée des génériques.
ArrayList myList = new ArrayList();
myList.Add("abc");
myList.Add("def");
myList.Add("ghi");
Vous ne voulez pas avoir à dire:
foreach(object item in myList)
{
string current = (string)item;
Dans un monde sans les génériques que vous devez savoir à l'avance quels types sont dans une liste, et vous avez presque toujours n'avoir que des connaissances. Mais cette information n'est pas enregistrée dans le système de type. Par conséquent, vous devez indiquer au compilateur d'une certaine manière, et vous le faire en disant:
foreach(string item in myList)
C'est votre affirmation au compilateur que la liste est complète de chaînes, tout comme une fonte est une affirmation qu'un élément particulier est une chaîne de caractères.
Vous avez totalement raison que c'est une misfeature dans un monde avec des génériques. Car il serait en rupture de changer maintenant, nous sommes coincés avec elle.
La fonctionnalité est assez confus; quand j'ai commencé la programmation en C# j'ai supposé qu'il avait la sémantique de quelque chose comme:
while(enumerator.MoveNext())
{
if (!(enumerator.Current is string) continue;
string item = (string)enumerator.Current;
Qui est, "pour chaque objet de type string dans cette liste, procédez de la manière suivante", quand il est vraiment "pour chaque objet dans cette liste affirmer que l'élément est une chaîne de caractères et de faire ce qui suit..." (Si l'ancien est exactement ce que vous voulez, puis utilisez l' OfType<T>()
méthode d'extension.)
La morale de l'histoire: les langues à la fin avec l'étrange "héritage" fonctionnalités lorsque vous massivement changer le type de système dans la version 2.
Si le compilateur produire un avertissement pour ce cas, un code moderne, où les médicaments génériques sont-ils utilisés?
Je considère que c'est. Notre recherche a montré que
foreach(Giraffe in listOfMammals)
est si commun que la plupart du temps, nous serait donner un avertissement pour le code est correct. Qui crée des ennuis pour tout le monde qui se compile avec "mises en garde comme des erreurs" est activée, et c'est en général la méchanceté d'avoir un avertissement sur le code qui est oui peut-être un peu malodorante, mais vraiment bon. Nous avons décidé de ne pas poursuivre l'avertissement.
Il existe d'autres situations où le compilateur C# invisible insère des conversions explicites?
Oui. En fait, quelqu'un a posé une question à ce sujet, juste quelques heures après celui-ci:
Compilateur remplace cast explicite à mon propre type de cast explicite .NET type?
Il y a quelques fort obscure de l'interopérabilité des scénarios où les conversions explicites sont insérés en tant que bien.