2010-10-26 14 views
13

Recientemente me sorprendió descubrir que aparentemente el compilador no es estricto al comparar referencias de interfaz y me pregunto por qué funciona de esta manera.¿Por qué se pueden comparar referencias de interfaz C# sin relación sin error del compilador?

consideran este código:

class Program 
{ 
    interface I1 {} 
    interface I2 {} 
    class C1 : I1 {} 
    class C2 : I2 {} 

    static void Main(string[] args) 
    { 
     C1 c1 = new C1(); 
     C2 c2 = new C2(); 

     I1 i1 = c1; 
     I2 i2 = c2; 

     bool x = c1 == c2; 
     bool y = i1 == i2; 
    } 
} 

El compilador dice que no puedo comparar c1 == c2, que sigue. Los tipos no tienen ninguna relación. Sin embargo, me permite comparar i1 == i2. Esperaría que fallara aquí con una falla en tiempo de compilación, pero me sorprendió descubrir que puede comparar cualquier interfaz con cualquier otra y el compilador nunca se quejará. Podría comparar, por ejemplo (I1)null == (IDisposable)null y no hay problema.

¿Las interfaces no son objetos? ¿Son un tipo especial de referencia? Mi expectativa sería que un == daría como resultado una comparación de referencia directa o una llamada a los equivalentes virtuales de la clase concreta.

¿Qué me estoy perdiendo?

+2

Para información, '==' se asocia típicamente con el operador op_Equality, no con el equivalente virtual (más comparación de referencia, pero ya lo cubrió) –

Respuesta

12

En primer lugar, tenga en cuenta que Hans cita la sección correcta de la especificación, pero que la edición de la especificación que está citando tiene un error tipográfico que es relevante para su pregunta. La especificación de C# 4 corregido dice:

El predefinida de referencia de tipo igualdad operadores requieren uno de los siguiente:

(1) ambos operandos son un valor de un tipo conocido por ser un tipo de referencia o el literal nulo. Además, existe una conversión de referencia explícita del tipo de cualquiera de los operandos al tipo del otro operando.

(2) Un operando es un valor de tipo T donde T es un parámetro de tipo y el otro operando es el literal nulo. Además, T no tiene el valor tipo restricción.

A menos que una de estas condiciones sea verdadera, se produce un error de tiempo de enlace .

Esto explica su observación. Hay una conversión de referencia explícita entre dos interfaces cualquiera porque dos instancias de dos interfaces diferentes podrían ser haciendo referencia al mismo objeto. Podría haber una clase C3 que implemente tanto I1 como I2, y podría estar haciendo una comparación de referencia de la misma instancia de C3, una convertida a I1 y la otra convertida a I2.

+0

Muchas buenas respuestas aquí, pero la más completa responde mi pregunta. Gracias. – scobi

13

supongo que esto fue hecho de manera tal, ya que puede tener un tipo de heredar ambas interfaces y para este caso, la comparación podría ser útil:

interface I1 {} 
interface I2 {} 
class C1 : I1, I2 {} 

Así, en el primer caso compilador definitivamente sabe que los objetos son diferente pero en el segundo caso podrían no serlo.

+0

Explicación funciona para mí +1 – gn22

0

Mi expectativa sería que a == daría como resultado una comparación de referencia directa o una llamada a los equivalentes virtuales de la clase concreta.

Esto es cierto, pero el compilador no lo sabe. Esto se determinaría en tiempo de ejecución.

4

Se describe muy bien en el C# Language Specification, capítulo 7.9.6 "operadores Referencia Tipo de igualdad":

El tipo de referencia predefinido igualdad operadores son:

== operador bool (objeto x, objeto y);
bool operator! = (Objeto x, objeto y);

Los operadores devuelven el resultado al comparar las dos referencias por igualdad o no igualdad.

Desde los predefinida tipo de referencia de igualdad operadores aceptan operandos de tipo objeto, que se aplican a todos los tipos que no declaran == operador aplicable y el operador! = Miembros. Por el contrario, los operadores aplicables de igualdad definida por el usuario ocultan efectivamente los operadores de referencia predefinidos de igualdad de tipos .

la referencia operadores tipo de igualdad predefinidos requieren una de la siguiente:
• ambos operandos son valores de tipo de referencia o en el literal nulo. Además, existe una conversión implícita estándar (§6.3.1) del tipo de cualquiera de los dos operandos al tipo de .
• Un operando es un valor de tipo T donde T es un tipo-parámetro y el otro operando es el nulo literal. Además, T no tiene el valor tipo restricción.

A menos que una de estas condiciones sea verdadera, se produce un error en tiempo de compilación. implicaciones notables de estas reglas son:
• Es un error de en tiempo de compilación para utilizar el tipo de igualdad referencia predefinido operadores para comparar dos referencias que son conocidos por ser diferente en tiempo de compilación. Por ejemplo, si los tipos de tiempo de compilación de los operandos son dos tipos de clase A y B, y si ni A ni B se deriva de la otro, entonces sería imposible para los dos operandos para hacer referencia al mismo objeto. Por lo tanto, la operación es considerada un error en tiempo de compilación.

El último párrafo es por qué recibe el error.

+2

Tenga en cuenta que está citando del C# 3.0 especificación, que contiene un error tipográfico que es relevante para esta pregunta. "implícito" arriba debe decir "explícito". –

Cuestiones relacionadas