2011-09-28 12 views
5

Tengo dos clases, una se deriva de CheckBoxList y la segunda de DropDownList. El código dentro de ellos es exactamente lo mismo. La única diferencia es que necesito primero uno en los lugares donde necesito mostrar la lista de casilla de verificación y el segundo para mostrar la lista desplegable. A continuación se muestra el código:Cómo crear una subclase común para eliminar el código duplicado

using System; 
using System.Collections.ObjectModel; 
using System.Web.UI.WebControls; 

    namespace Sample 
    { 
     public class MyCheckBoxList : CheckBoxList 
     { 
      public int A { get; set; } 
      public int B { get; set; } 
      protected override void OnLoad(EventArgs e) 
      { 
       //dummy task 
       Collection<int> ints = new Collection<int>(); 
       //........ 
       this.DataSource = ints; 
       this.DataBind(); 
      } 
     } 
    } 

El segundo

using System; 
using System.Collections.ObjectModel; 
using System.Web.UI.WebControls; 

namespace Sample 
{ 
    public class MyDropDownList : DropDownList 
    { 
     public int A { get; set; } 
     public int B { get; set; } 
     protected override void OnLoad(EventArgs e) 
     { 
      //dummy task 
      Collection<int> ints = new Collection<int>(); 
      //........ 
      this.DataSource = ints; 
      this.DataBind(); 
     } 
    } 
} 

Ahora bien, como se puede ver el código interno es exactamente el mismo que quiero evitar. ¿Cómo puedo hacer una clase común para eliminar la duplicación de código?

+3

+1 por esforzarse por reducir la redundancia en su código. Sin embargo, su pregunta puede ser más adecuada aquí: http://codereview.stackexchange.com/ –

+0

@KileyNaro: Cool para aprender sobre la revisión del código, no sabía que existía. No creo que sea una mala coincidencia para SO tampoco. Buena pregunta, creo. +1 –

Respuesta

3

Puede crear una tercera clase

public class Entity 
{ 
    public int A { get; set; } 
    public int B { get; set; } 
    Collection<int> GetCollection() 
    { 
     //dummy task 
     Collection<int> ints = new Collection<int>(); 
     //........ 
     return ints; 
    } 
} 

y luego usarlo en otras clases

public class MyDropDownList : DropDownList 
{ 
    public MyDropDownList() { Entity = new Entity(); } 

    public Entity {get;set;} 
    protected override void OnLoad(EventArgs e) 
    { 
     this.DataSource = Entity.GetCollection(); 
     this.DataBind(); 
    } 
} 
+0

pero esto lleva a buscar mis propiedades como Entity.A y Entity.B. Quiero evitar eso. Quiero las propiedades directamente desde mis páginas aspx. –

+0

@Rocky: encapsula la entidad, hazla privada y crea una propiedad en tu clase para acceder a ella. – Arjang

+0

+1 por usar composición, lo único que quedaba era hacer que Entity fuera interna, usando Encapsulation de manera externa no es necesario – Arjang

0

no se puede, porque C# no soporta la herencia múltiple de aplicación (y ya está la subclasificación) podría refactorizar parte del código en una tercera clase y hacer que cada una de sus clases tenga una instancia y delegarle llamadas.

podría intentar algo como esto: http://www.codeproject.com/KB/architecture/smip.aspx, pero parece que es mucho trabajo.

+0

Solo porque tengo curiosidad y realmente no tengo ni idea, ¿te importaría explicar cómo se pueden usar los delegados para lograr lo que el OP está buscando? –

+1

solo quise delegar las llamadas al tercer objeto. No me refería al delegado de C#. –

+0

Gracias por la aclaración. ¡Entiendo lo que dices! –

0

Usas la composición, haces otra clase que no está relacionada con estas dos clases, luego tienes el código común en esa, cuando necesitas usar el código en cualquiera de las clases que haces una instancia, también puedes usarlo a fondo una interfaz. No es necesario usar inheritnece.

Actualización: código de abajo (Modificado el código ya proporcionada por meziantou)

internal interface IEntity 
    { 
     int A { get; set; } 
     int B { get; set; } 
     Collection<int> GetCollection { get; } 
    } 

    internal class Entity : TrialBalanceHTMLToDataTable.TrialBalance.IEntity 
    { 
     public int A { get; set; } 
     public int B { get; set; } 
     public Collection<int> GetCollection 
     { 
      get{ 
      //dummy task 
      Collection<int> ints = new Collection<int>(); 
      //........ 
      return ints; 
      } 
     } 
    } 


    public class MyDropDownList : DropDownList 
    { 
     public MyDropDownList() { _Entity = new Entity(); } 

     private IEntity _Entity { get; set; } 
     protected override void OnLoad(EventArgs e) 
     { 
      this.DataSource = _Entity.GetCollection; 
      this.DataBind(); 
     } 
    } 
+1

-1 para decir que una interfaz resolverá el problema; las definiciones aún se duplicarán entre las dos clases que implementan la interfaz. Pero obtienes +1 por sugerir que el código común se mueva a otra clase ... ¡por lo que saldas! –

+0

@KileyNaro: LOL :), ¡Las interfaces no resuelven problemas, solo te permiten uniformarlas! – Arjang

+0

@KileyNaro: ¡NO! la clase común implementará la interfaz, las otras dos clases solo la usarán para hablar con la clase que la implementa. La idea no era implementar las interfaces en dos clases diferentes. – Arjang

0

Parecería que lo que está tratando de lograr es tener una sola clase, es decir MyDropDownList, ser capaz de heredar propiedades del DropDownList, y para tener la clase MyCheckBox heredar propiedades de la clase CheckBox, mientras que tener tus dos clases My * tiene algunas propiedades adicionales, que son idénticas.

Como han sugerido otros, la manera más fácil de lograr esto sería a través de Multiple Inheritance. Específicamente en su ejemplo, eso significaría crear una clase (posiblemente abstract) que describa los atributos compartidos entre MyDropDownList y MyCheckBox, y luego tener esas dos clases heredadas de sus respectivas bases System.Web.UI.WebControls así como también esta "compartida". " clase. Sin embargo, como se ha dicho, C# doesn't support multiple inheritance. De Chris Brumme a través de ese enlace:

El número de lugares donde mi es realmente apropiada es en realidad muy pequeña. En muchos casos, la herencia de interfaz múltiple puede hacer el trabajo en su lugar. En otros casos, es posible que pueda usar encapsulación y delegación.

Es posible que también haya considerado usar Interfaces. Esto, como habrás descubierto, sería una elección inapropiada para tu solución como . Una interfaz solo te permite definir que hay ciertas propiedades y métodos en una clase, pero no cómo se definen las propiedades o los métodos. De nuevo, esta es una opción inapropiada para eliminar código duplicado.

¿Qué significa esto para usted? Bueno, si está buscando escribir una clase MyDropDownList que admita las sintaxis myCustomDDLInstance.SelectedIndex y myCustomDDLInstance.A, tendrá que hacer un poco de "magia". ¡Pero el hecho de que su idioma no sea compatible con lo que está tratando de hacer debería levantar una bandera roja! No es necesariamente incorrecto, pero debería ser un indicador fuerte de que es posible que desee volver a examinar su diseño.

Supongo que la parte duplicada de las dos clases puede ser independiente ya que es una entidad lógica propia. Esto significa que puede crear justificadamente su propia clase para mantener estas propiedades y métodos compartidos. Esto es lo que obtenemos:

SampleControl.cs

public class SampleControl 
{ 
    public int A { get; set; } 
    public int B { get; set; } 

    public Collection<int> MysteryCollection 
    { 
     get 
     { 
      Collection<int> ints = new Collection<int>(); 
      //........ 
      return ints; 
     } 
    } 
} 

Si CSharp hizo apoyo en el hecho de la herencia múltiple, la clase MyDropDownList podría heredar de ambos DropDownList y SampleControl y que estaría hecho. Pero, nuevamente, esto no es posible.

Entonces, ¿cómo logramos su objetivo? Es un poco intrincado, pero puede Encapsulate sus propiedades y métodos compartidos en cada una de sus clases personalizadas. He aquí un ejemplo para el MyDropDownList clase (nota que MyCheckBoxList sería lo mismo, sólo cambia el nombre de la clase:

public class MyDropDownList : DropDownList 
{ 
    private SampleControl mySampleControl { get; set; } 

    public int A 
    { 
     get 
     { 
      return mySampleControl.A; 
     } 

     set 
     { 
      mySampleControl.A = value; 
     } 
    } 

    public int B 
    { 
     get 
     { 
      return mySampleControl.B; 
     } 

     set 
     { 
      mySampleControl.B = value; 
     } 
    } 

    public MyDropDownList() 
    { 
     mySampleControl = new SampleControl(); 
    } 

    protected override void OnLoad(EventArgs e) 
    { 
     //dummy task 
     this.DataSource = mySampleControl.MysteryCollection; 
     this.DataBind(); 
    } 
} 

Una clase diseñada de esta manera, mientras que un poco complicado, debe cumplir con la sintaxis tipo que usted está buscando para.

Como nota final os animo encarecidamente a por lo menos posibilidad de volver a examinar su diseño y ver si hay una mejor manera para que pueda acercarse a su jerarquía de clases. Mi recomendación es que si sus atributos compartidos pueden existir por sí mismos como una entidad lógica, probablemente deberían ser su propia clase. Y si es así, esa clase es probab Es un miembro legítimo y lógico de sus clases MyDropDownList y MyCheckBox. Lo que significa que debe utilizar la sintaxis myDropDownListInstance.SharedAttributesClassName.A. Es a la vez más explícito y más honesto.

+0

This is Composition, http://en.wikipedia.org/wiki/Composition_over_inheritance – Arjang

Cuestiones relacionadas