2008-10-27 6 views
8

Tengo una clase con algunos métodos abstractos, pero quiero poder editar una subclase de esa clase en el diseñador. Sin embargo, el diseñador no puede editar la subclase a menos que pueda crear una instancia de la clase padre. Así que mi plan es reemplazar los métodos abstractos con stubs y marcarlos como virtuales, pero si hago otra subclase, no obtendré un error en tiempo de compilación si me olvido de implementarlos.¿Puedo forzar que las subclases anulen un método sin hacerlo abstracto?

¿Hay alguna manera de marcar los métodos para que tengan que implementarse por subclases, sin marcarlos como abstractos?

+0

¿Cómo se las arregló para diseñar la clase base en el diseñador? –

Respuesta

9

Bueno, podría hacer un código muy complicado que implique #if - es decir, en DEBUG es virtual (para el diseñador), pero en RELEASE es abstracto. Un verdadero dolor para mantener, sin embargo.

Pero aparte de eso: básicamente, no. Si desea soporte de diseñador, no puede ser abstracto, por lo que se queda con "virtual" (presumiblemente con el método base lanzando un NotImplementedException).

Por supuesto, las pruebas de su unidad verificarán que los métodos se hayan implementado, ¿sí? ;-P

En realidad, probablemente sería bastante fácil de probar a través de los genéricos - es decir, tener un método de prueba genérica de la forma:

[Test] 
public void TestFoo() { 
    ActualTest<Foo>(); 
} 
[Test] 
public void TestBar() { 
    ActualTest<Bar>(); 
} 

static void ActualTest<T>() where T : SomeBaseClass, new() { 
    T obj = new T(); 
    Assert.blah something involving obj 
} 
0

Sé que no es exactamente lo que está después, pero se podría hacer todos tus stubs en la clase base lanzan la NotImplementedException. Entonces, si alguna de sus subclases no las ha anulado, obtendría una excepción en tiempo de ejecución cuando se llama al método en la clase base.

+0

Sí, lo he hecho, pero quiero una excepción en tiempo de compilación. – Simon

0

La clase Component contiene una propiedad booleana llamada "DesignMode" que es muy útil cuando desea que su código se comporte de manera diferente en el diseñador que en el tiempo de ejecución. Puede ser de alguna utilidad en este caso.

5

Puede utilizar la referencia al idioma de implementación en su clase.

public class DesignerHappy 
{ 
    private ADesignerHappyImp imp_; 

    public int MyMethod() 
    { 
     return imp_.MyMethod()  
    } 

    public int MyProperty 
    { 
     get { return imp_.MyProperty; } 
     set { imp_.MyProperty = value; } 
    } 
} 

public abstract class ADesignerHappyImp 
{ 
    public abstract int MyMethod(); 
    public int MyProperty {get; set;} 
} 

DesignerHappy simplemente expone la interfaz que desee, pero reenvía todas las llamadas al objeto de aplicación. Extiende el comportamiento subclasificando ADesignerHappyImp, lo que te obliga a implementar todos los miembros abstractos.

Puede proporcionar una implementación predeterminada de ADesignerHappyImp, que se utiliza para inicializar DesignerHappy de forma predeterminada y exponer una propiedad que le permite cambiar la implementación.

0

Como regla general, si no hay ninguna manera en un lenguaje para hacer algo que por lo general significa que hay una buena razón conceptual para no hacerlo.

A veces esto será culpa de los diseñadores de idiomas, pero no a menudo. Usualmente encuentro que saben más sobre el diseño del lenguaje que yo ;-)

En este caso, usted desea que un método virtual no anulado arroje una excepción de tiempo de compilación (en lugar de uno de tiempo de ejecución). Básicamente un método abstracto entonces.

Hacer que los métodos virtuales se comporten como los abstractos va a crear un mundo de confusión para ti más adelante en la línea.

Por otro lado, el diseño del complemento VS a menudo no está al mismo nivel (eso es un poco injusto, pero ciertamente se aplica menos rigor que en la etapa de diseño del lenguaje, y con razón).Algunas herramientas de VS, como el diseñador de clases y los editores actuales de WPF, son buenas ideas, pero aún no están completas.

En el caso que usted está describiendo, creo que tiene un argumento para no usar el diseñador de clases, no es un argumento para hackear su código.

En algún momento (tal vez en el próximo VS) van a poner en orden cómo el diseñador de la clase trata con las clases abstractas, y luego tendrás un truco sin la menor idea de por qué fue codificado de esa manera.

Siempre debe ser el último recurso para hackear su código para adaptarse al diseñador, y cuando intenta mantener los piratas informáticos mínimos. Encuentro que generalmente es mejor tener un código conciso y legible que tenga sentido rápidamente sobre el código bizantino que funciona en las herramientas rotas actuales.

+0

Esto ha sido durante mucho tiempo un defecto en Visual Studio, pero no se puede sacrificar la legibilidad y el mantenimiento por algo que la herramienta ha carecido durante años. ¿Alguna vez ha tratado de modificar programáticamente WinForms complejos? Lleva mucho más tiempo y es fuente de mucha frustración. Microsoft incluyó al Diseñador por una razón, y creo que es completamente legítimo hacer un poco de "piratería" para mejorar el mantenimiento de su proyecto. Solo asegúrese de documentar lo que está haciendo y por qué. – Tim

+0

@Tim - Realmente no estaba diciendo que no era legítimo, mi punto era que debería ser un último recurso para piratear el código para adaptarlo a las herramientas. En este caso, creo que la mejor solución es que, en la respuesta aceptada, arroje 'NotImplementedException' en los miembros virtuales y pruebe el código en la unidad. – Keith

1

Tenga en cuenta que "DesignMode" no se establece en el constructor. Se establece después de que VS analiza el método InitializeComponents().

0

utilizar MS como un ejemplo ...

Microsoft hace esto con las plantillas de control de usuario en Silverlight. #if es perfectamente aceptable y es dudoso que el herramental funcione a su alrededor pronto. IMHO

+0

¡cita requerida! – manas

Cuestiones relacionadas