2008-10-31 23 views
16

Hoy encuentro que una clase C# puede heredar una interfaz tanto de manera implícita como explícita. Esto me sorprende. Si C# funciona de esta manera, una instancia puede comportarse de manera diferente cuando se hace referencia a ella de manera diferente.¿Por qué una clase C# puede heredar de una interfaz de manera implícita y explícita?

interface IFoo 
{ 
    void DoSomething(); 
} 

class Foo : IFoo 
{ 
    #region IFoo Members 
    public void DoSomething() 
    { 
     Console.WriteLine("do something implicitly"); 
    } 
    #endregion 

    #region IFoo Members 
    void IFoo.DoSomething() 
    { 
     Console.WriteLine("do something explicitly"); 
    } 
    #endregion 
} 


     Foo f = new Foo(); 
     f.DoSomething(); 

     ((IFoo)f).DoSomething(); 

Por encima de carreras de código y de salida

do something implicitly 
do something explicitly 

creo que este diseño de C# hacer inconsistencia de comportamiento. Quizás es obligatorio que una clase C# pueda heredar de una interfaz de manera implícita o explícita, pero no ambas.

¿Hay alguna razón por la cual C# está diseñado de esa manera?

+0

No me di cuenta de que podía hacer ambas cosas. Eso parece un poco tonto ... –

+0

No es tonto. Lee las respuestas. –

+0

Disculpa por la doble repetición, estaba intentando agregar "explicit-interface-member-implementation" como una etiqueta (ese es el nombre de la función que estás usando), pero aparentemente esa etiqueta sería demasiado larga. :) – Rytmis

Respuesta

11

En su ejemplo no implemente IFoo implícita y explícitamente. Usted solo implementa IFoo.DoSometing() explícitamente. Tienes un nuevo método en tu clase llamado DoSomething(). No tiene nada que ver con IFoo.DoSomething, excepto que tiene el mismo nombre y parámetros.

+0

¿Y cómo se implementaría implícitamente? –

+0

solo si no había una implementación explícita –

+0

Entonces, "la clase C# puede heredar una interfaz de manera implícita y explícita al mismo tiempo" es en realidad una ilusión. Una clase puede heredar una interfaz una vez en realidad. –

13

Cada clase que implementa una interfaz tiene una asignación de entre los miembros de esa clase y los miembros de la interfaz. Si la clase explícitamente implementa un miembro de interfaz, entonces la implementación explícita se siempre se asignará a la interfaz. Si no hay una implementación explícita, se espera una implementación implícita, y esa será mapeada a la interfaz.

Cuando una clase tiene el mismo nombre de miembro y tipos asociados como una interfaz pero también implementa explícitamente el miembro correspondiente de la interfaz, a continuación, de la clase de implementación "implícita" no considerada es una implementación de la interfaz en total (a menos que la implementación explícita lo llame).

Además de diferentes significados en cada caso en que la clase implementa múltiples interfaces con el mismo nombre miembro/tipos, incluso con sólo una interfaz, la clase se considera que tiene una interfaz implícita que pueda tener el mismo miembro/types como la única interfaz, pero todavía significa algo diferente.

+0

¿Es esta interfaz implícita una interfaz real, o simplemente la clase que expone una interfaz, es decir, es un tipo, aunque oculto? – ProfK

+0

Solo me refiero a lo que expone la clase. El CLR no diferencia entre la implementación de una clase y su interfaz inherente (es decir, no puede implementar la interfaz de otra clase y sustituirla a menos que la interfaz sea un tipo de Interfaz definido por separado). –

2

Herencia múltiple: ¿Qué sucede si deriva de dos interfaces que definen el mismo método para diferentes propósitos?

interface IMoveable 
    { 
    public void Act(); 
    } 

    interface IRollable 
    { 
    public void Act(); 
    } 

    class Thing : IMoveable, IRollable 
    { 
    //TODO Roll/Move code here 

    void IRollable.Act() 
    { 
     Roll(); 
    } 

    void IMoveable.Act() 
    { 
     Move(); 
    } 
    } 
7

Esto lo hace más flexible para cuando hay colisiones. En particular, mira IEnumerator y IEnumerator<T> - ambos tienen una propiedad Current, pero de diferentes tipos. Usted tiene para utilizar la implementación de interfaz explícita a fin de implementar ambos (y el formulario genérico amplía la forma no genérica).

+0

IIRC este es el ejemplo exacto que Jeff Richter usa para EIMI en el impresionante CLR a través de C#. – Quibblesome

+0

Probablemente sea el que aparece más a menudo por un factor masivo :) –

+0

También he tenido la propiedad "this [string]" en este escenario. Tuve una clase con un indexador de cadenas, y luego quería implementar IDataErrorInfo. Mismo problema: tuve que implementar el indexador de cadenas para el error explícitamente. –

0

Chicos, gracias por sus respuestas.

Resulta que "la clase C# puede heredar una interfaz de manera implícita y explícita al mismo tiempo" es en realidad una ilusión. En realidad, una clase puede heredar una interfaz por una vez.

En la pregunta original, el método "DoSomething" parece una interfaz "implícitamente implementada" IFoo (el método en realidad es generado por VS2008), pero en realidad NO lo es. Con la implementación explícita de la interfaz IFoo, el método "DoSomething" se convierte en un método normal que no tiene nada que ver con IFoo excepto con la misma firma.

Todavía creo que es un diseño complicado de C#, y es fácil de usar por error. Diga, tengo un código como este

 Foo f = new Foo(); 
     f.DoSomething(); 

Ahora, quiero refactorizarlo al código siguiente. Parece perfectamente bien, pero el resultado de la ejecución es diferente.

 Action<IFoo> func = foo => foo.DoSomething(); 
     func(f); 
+1

Es complicado porque uno pensaría que Foo es un IFoo como si fuera un BaseFoo pero no lo es. Es mejor pensar que un Foo tiene el * role * de un IFoo y cuando accedes a un Foo como un IFoo estás cambiando su * role * y * posiblemente * its * behavior * también. –

+0

De hecho afirmaré que es un diseño complicado de la clase Foo tener dos métodos diferentes con el mismo nombre y parámetros. Otro ejemplo de lo que puede usar para confundir a las personas es usar la nueva palabra clave como un modificador de método. Nunca lo uso porque es confuso, pero podría tener que hacerlo algún día. – Hallgrim

Cuestiones relacionadas