Warum erlaubt der C # -Compiler das Kompilieren und löst beim Ausführen eine Laufzeitausnahme aus?
class Program
{
static void Main(string[] args)
{
IEnumerable<Test> list = new List<Test>() { new Test() };
foreach(IDisposable item in list)
{
}
}
}
public class Test
{
}
Dies wird mit jeder Schnittstelle kompiliert und nicht kompiliert, wenn Sie IDisposable durch eine konkrete Klasse ersetzen.
c#
covariance
ekalchev
quelle
quelle
Test
denen es implementiert wirdIDisposable
. Tatsächlich versucht foreach, jedes Element in die Schnittstelle umzuwandeln, und löst eine Ausnahme aus, wenn dies fehlschlägt. Das gleiche, als würdest du schreiben(IDisposable)currentElement
. Ich kann jedoch nicht verstehen, warum es nicht in der konkreten Klasse kompiliert werden sollte.foreach (IDisposable item in list.OfType<IDisposable>())
Antworten:
Die
foreach
Schleife enthält eine implizite Besetzung. Es ist ungefähr so:Vor den Generika war das viel einfacher, als den Quellcode eingeben zu müssen. Jetzt ist es nicht so wichtig, aber es wäre seltsam, wenn es nicht kompiliert würde. Beachten Sie, dass der Compiler wird prüfen, ob es zumindest ist machbar . Wenn Sie das verwenden
foreach (string item in list)
, wird es nicht kompiliert, weil aTest
nicht a sein kannstring
- aber aTest
kann a seinIDisposable
, weil es auf eine Instanz einer UnterklasseTest
dieser Implementierungen verweisen könnteIDisposable
. Wenn Sie dieTest
Klasse versiegeln, kann sie auch mit nicht kompiliertIDisposable
werden, da eineTest
Instanz dann nicht implementiert werden kannIDisposable
.Grundsätzlich wird es kompiliert, wenn eine Umwandlung von
Test
in den Iterationstyp kompiliert werden würde, und es wird sonst nicht kompiliert. Aber es wird zur Ausführungszeit fehlschlagen, wenn eine normale Besetzung auch zur Ausführungszeit fehlschlagen würde.quelle