2010-07-22 34 views
5

I tienen una interfaz de la siguiente manera¿Cómo implementar parcialmente un contrato en una clase base abstracta?

public interface IX 
    { 
     void MethodA(); 
     void MethodB(); 
    } 

Tengo dos contratos método de la interfaz MethodA y MethodB. Definiré un conjunto de clases que implementará la interfaz anterior. De estos dos métodos, MethodA es común para todos los tipos que implementarán la interfaz. Puedo definir una clase abstracta de la siguiente manera

public abstract class XBase:IX 
    { 
     public void MethodA() 
     { 
      // Common behaviour implementation 
     } 

     public abstract void MethodB(); 
    } 

Y heredar esta clase a todos los tipos que necesiten implementar la interfaz anterior. Funciona.

Pero aquí en la clase abstracta agrego 'public abstract void MethodB();'. Parece una repetición del contrato MethodB.

¿Por qué C# no permite la implementación parcial de la interfaz si la clase es abstracta ?. La interfaz anterior tiene solo dos métodos. supongamos que una interfaz tiene 10 métodos y 5 son funciones comunes y 5 no, ¿estamos obligados a agregar los 5 métodos que no son comunes en la clase abstracta?

+0

Just Curious ¿por qué querrías implementar una interfaz en una clase abstracta? Parece romper las relaciones is-a, actua como-a. – CkH

+0

@ Cameron: En realidad, creo que este es un enfoque muy bueno. En teoría, podría tener varias clases base abstractas diferentes que implementan la misma interfaz a través de un enfoque fundamentalmente diferente para su implementación. –

Respuesta

8

Porque la especificación del lenguaje C# lo dice. Capítulo 13.4.7:

Al igual que una clase no abstracta, una clase abstracta debe proporcionar implementaciones de todos los miembros de las interfaces que se enumeran en la lista de clase base de la clase.

Por qué los diseñadores de C# optaron por especificar el lenguaje como este probablemente sea mejor respondido por Eric Lippert. Personalmente, supongo que reducir las probabilidades de que se produzca ocultación involuntaria de métodos, produciendo mensajes de error que son muy difíciles de interpretar. Personalmente me habría sentido más cómodo al requerir el uso de la palabra clave reemplazos para la implementación del método de interfaz. Pero ellos eligieron no hacerlo.

+1

Hans Entiendo que se ha cumplido, pero es curioso saber por qué el lenguaje hace cumplir esto ?. Gracias por la respuesta – RAM

+3

Su punto sobre el ocultamiento involuntario de métodos está bien tomado; otra forma de decir que es que esta regla es otra manera en la que el diseño de C# funciona contra fallas de clase base frágiles. Sin embargo, señalaría que el beneficio más obvio de la regla actual es simplemente que es * muy fácil de entender *. Usted tiene una interfaz. Tienes una clase que implementa la interfaz. * Se requiere que la clase implemente todos los miembros de la interfaz, punto *. Esa regla es fácil de explicar, es fácil de verificar, es fácil producir errores claros y es fácil corregir las violaciones. –

1

La razón por la que no es compatible es porque su superclase no cumple el contrato. La única forma en que una clase abstracta puede forzar la implementación en sus subclases es definir métodos abstractos.

Si no desea que la clase abstracta tenga definidos esos métodos abstractos, debe indicar a las subclases que implementen la interfaz.

La pregunta debería ser, ¿por qué sería un problema tener 5 métodos abstractos en su superclase?

+1

Creo que lo que está logrando RAM es en esta situación el compilador podría generar firmas de métodos de interfaz abstractos de forma automática. –

+1

@Sam - podría, pero eso sería vagamente confuso para alguien que implementa una subclase. No pueden ver necesariamente la interfaz en la superclase, entonces, ¿cómo sabrían lo que tenían que implementar? – pdr

+1

Pdr como SAM indicó que puede generar esos métodos abstractos internamente o puede encontrarlos desde la jerarquía. Supongamos que estoy heredando de la superclase, veré que la superclase implementa la interfaz y no proporciona implementación a todos los contratos de método, lo que significa que debo proporcionar la implementación a los métodos de interfaz que no están implementados en la superclase. . ¿Tiene sentido esto? – RAM

0

Las interfaces pasar a lo largo del requisito de contrato entre sí, por lo que en la medida que tiene IFoo y IBar : IFoo, a continuación, las clases que heredan de IBar deben implementar ambas interfaces, como claramente IBar no se puede aplicar a los miembros de IFoo sí. Por qué este comportamiento no se puede extender a clases base abstractas, no lo sé. Estoy seguro de que hay una buena razón, y desde que Hans publicó la especificación, obviamente es intencional.

Como favor, no intente esto en el enfoque casa, usted podría hacer algo como

class Derived : Base, IFoo 
{ 
    public void MethodB() 
    { 
    } 
} 

abstract class Base 
{ 
    public Base() 
    { 
     if (!(this is IFoo)) 
      throw new InvalidOperationException("must implement IFoo"); 
    } 

    public void MethodA() { } 
} 

interface IFoo 
{ 
    void MethodA(); 
    void MethodB(); 
} 

que tiene la base abstracta implementar los métodos que quiere y luego obligar a las clases derivadas para implementar el resto de haciendo cumplir que las clases derivadas implementan la interfaz. Las clases derivadas serían responsables de implementar los métodos que aún no están en la clase base.El problema con este enfoque es que este es un requisito de tiempo de ejecución, no de compilación.

0

¿Cómo manejar una situación en la que usted tiene

interface IFoo { 
    void MethodA(); 
    void MethodB(); 
} 
abstract class Base: IFoo { 
    public void MethodA() {} 
    // MethodB gets implicitly generated 
} 
class Derived: Base { 
    public void MethodB() {} 
} 

Podría entonces hacer esto:

Base myBase = ... 
myBase.MethodB(); 

Ok se puede, ya que MethodB es implícita. Pero, ¿qué pasa si luego decide eliminar la interfaz IFoo de la clase Base? Acaba de romper el contrato de Base ... La solución sería que los métodos generados serían implementaciones de interfaz explícitas, pero eso trae otro tipo de dolor.

0

Se puede pasar de 'abstracta' a 'virtual' en la declaración del método y proporcionar una afirmación:

public abstract void MethodB(); 

convierte

public virtual void MethodB() 
{ 
    Contract.Require(your condition); 
} 
0

No creo clase abstracta o interfaz está haciendo cualquier injusticia en su escenario más bien según los principios SÓLIDOS (específicamente: Principio de Segregación de interfaz): https://msdn.microsoft.com/en-us/library/dn178470(v=pandp.30).aspx

Dice que las interfaces grandes deben dividirse en más pequeños y más específicos para que las clases de los clientes no se vean obligadas a implementar métodos que no usan en absoluto. Utilizar este principio resolvería su problema.

Cuestiones relacionadas