¿Por qué no hay error de comstackción cuando emito una clase a una interfaz que no implementa?

Si bash una conversión no válida de una clase a una interfaz, el comstackdor no se queja (el error ocurre en tiempo de ejecución); Sin embargo, se queja, si bash un reparto similar a una clase abstracta.

class Program { abstract class aBaz { public abstract int A { get; } } interface IBar { int B { get; } } class Foo { public int C { get; } } static void Main() { Foo foo = new Foo(); // compiler error, as expected, since Foo doesn't inherit aBaz aBaz baz = (aBaz)foo; // no compiler error, even though Foo doesn't implement IBar IBar bar = (IBar)foo; } } 

¿Por qué el comstackdor no rechaza el reparto de Foo a IBar , cuando (aparentemente?) No es válido? O, para pasar la pregunta, si el comstackdor permite esta conversión “no válida” a la interfaz IBar , ¿por qué no permite la conversión “no válida” similar a la clase abstracta aBaz ?

Debe comprender el sistema de herencia de .Net para ver por qué esto tiene sentido. En .Net, una clase puede heredar de una sola clase base pero puede implementar cualquier número de interfaces.

 class Program { abstract class aBaz { public abstract int A { get; } } interface IBar { int B { get; } } class Foo { public int C { get; } } class BarableFoo : Foo, IBar { public int C { get; } } static void Main() { // This is why the compiler doesn't error on the later cast Foo foo = new BarableFoo(); // compiler error: aBaz is a class and the compiler knows that // Foo is not a _subclass_ of aBaz. aBaz baz = (aBaz)foo; // no compiler error: the class Foo does not implement IBar, however at runtime // this instance, "foo", might be a subclass of Foo that _implements_ IBar. // This is perfectly valid, and succeeds at runtime. IBar bar = (IBar)foo; // On the other hand... foo = new Foo(); // This fails at runtime as expected. bar = (IBar)foo; } } 

En el ejemplo original extremadamente simple de la pregunta, parece que el comstackdor podría detectar que esta instancia de foo nunca se podrá convertir en IBar, pero eso es más una advertencia “agradable de tener” que una cuestión de corrección del idioma.

El punto principal de una conversión es suprimir el error del comstackdor.
(por ejemplo, si sabe que foo es en realidad una instancia de un subtipo que implementa la interfaz)

Si el comstackdor puede probar que es imposible que el lanzamiento tenga éxito, aún dará un error. (p. ej., si se convierte en una clase que no está en su jerarquía)

Y para demostrar que el comstackdor no es estúpido, hay un caso real cuando el lanzamiento fallará en el tiempo de comstackción: si el comstackdor puede probar que ninguna otra clase puede derivar de la clase, fallará el envío a las interfaces en el momento de la comstackción:

 sealed class NoBar { } struct NoBarValue { } IBar noBar = (IBar)(new NoBar()); // fails at compile time IBar noBarValue = (IBar)(new NoBarValue()); // fails at compile time 

En el primer caso (la clase NoBar ) se sella explícitamente (y, por lo tanto, ninguna clase derivada puede implementar IFoo) y el comstackdor sabe que no implementa IBar sí, por lo que puede fallar en el momento de la comstackción. El segundo caso ( NoBarValue ) es similar con la única diferencia de que los tipos de valor (struct) están sellados implícitamente.