Pourquoi le compilateur C # permet-il de compiler et lève une exception d'exécution lors de l'exécution?
class Program
{
static void Main(string[] args)
{
IEnumerable<Test> list = new List<Test>() { new Test() };
foreach(IDisposable item in list)
{
}
}
}
public class Test
{
}
Cela se compile avec n'importe quelle interface et ne se compile pas si vous remplacez IDisposable par une classe concrète.
La boucle foreach
a un transtypage implicite. C'est à peu près comme ça:
using (IEnumerator<Test> iterator = list.GetEnumerator())
{
while (iterator.MoveNext())
{
IDisposable item = (IDisposable) iterator.Current;
// Body of foreach loop here
}
}
Avant les génériques, c'était beaucoup plus pratique que de devoir transtyper le code source. Maintenant, ce n'est pas si important, mais il serait étrange qu'il ne compile pas. Notez que le compilateur va vérifier qu'il est au moins faisable. Si vous utilisez foreach (string item in list)
qui ne compilerait pas, car un Test
ne peut pas être un string
- mais un Test
can être un IDisposable
, car il pourrait faire référence à une instance d'une sous-classe de Test
qui implémente IDisposable
. Si vous rendez la classe Test
scellée, elle ne pourra pas être compilée même avec IDisposable
, car une instance Test
ne pourra pas implémenter IDisposable
.
Fondamentalement, il se compilera si un transtypage de Test
vers le type d'itération se compilait, et échouera à la compilation sinon. Mais il échouera au moment de l'exécution si une conversion normale échouait également au moment de l'exécution.