2016-07-18 6 views
0

Betrachten Sie den folgenden Codein C#, warum ich eine Schnittstelle zu jeder Art ohne Compiler-Fehler werfen kann

IDisposable foo = <something>; 
ArrayList bar = (ArrayList)foo; 

Dies sogar ohne Warnung kompiliert obwohl Arraylist IDisposable nicht implementiert.

Es scheint, dass Sie jede Schnittstelle in eine Klasse umwandeln können, die diese Schnittstelle nicht implementiert. Da die beiden Arten zur Kompilierungszeit offensichtlich sind, warum überprüft der Compiler das nicht?

+6

'ArrayList' ist nicht versiegelt, so dass Sie eine Unterklasse von' ArrayList' haben könnten, die 'IDisposable' implementiert. – Lee

+0

Ja, das könntest du tun, aber dann sollte der Compiler sicherlich erwarten, dass du ihn in deine Unterklasse wirfst. Dies würde Sie dazu zwingen, sich explizit mit den Typen zu beschäftigen, die Sie erwarten, was der Punkt einer stark typisierten Sprache zu sein scheint. – Andy

+0

Es ist, weil die C# Spezifikation so sagt. Siehe Abschnitt 6.2.4, um zu sehen, warum Lee korrekt ist. – Crowcoder

Antwort

1

Es wird nicht validiert, da es sich um eine gültige Besetzung handeln könnte.

public class Foo : ArrayList, IDisposable 
{ 
    ... 
} 
public class Bar : IDisposable 
{ 
    ... 
} 

Random rand = new Random(); 
public IDisposable SomtimesGetArrayList() 
{ 
    if(rand.Next(0,4) == 0) 
     return new Bar(); 

    return new Foo(); 
} 

//Elsewhere 
IDisposable foo = SomtimesGetArrayList(); 
ArrayList bar = (ArrayList)foo; 

3 von 4 Anrufen SomtimesGetArrayList ein Objekt zurück, das erfolgreich gegossen werden kann. Es ist zu viel Verarbeitungsaufwand für den Compiler, jeden Codepfad zu überprüfen und sicherzustellen, dass jeder mögliche Weg potenziell ein Objekt erzeugen könnte.

Wenn Sie jedoch eine sealed Klasse hatten, kann der Compiler weitere Annahmen treffen und es muss nicht jeder Pfad überprüft werden, um zu wissen, dass der Cast immer fehlschlägt, der folgende Code lautet will fail to compile.

using System; 

public class Program 
{ 
    public static void Main() 
    { 
     IDisposable foo = new Foo(); 
     Bar bar = (Bar)foo; 
    } 
} 

public class Foo : IDisposable 
{ 
    public void Dispose() 
    { 
    } 
} 

public sealed class Bar 
{ 
}