Pregunta

Tengo 100 clases que tienen algunos elementos similares y algunos únicos. He creado una interfaz que nombra esos elementos similares, por ejemplo: interfaz IAnimal. Lo que normalmente haría es:

class dog : IAnimal

Pero hay 100 clases y no tengo ganas de revisarlas todas y buscar aquellas a las que pueda aplicar IAnimal.

Lo que quiero hacer es esto:

dog scruffy = new dog();
cat ruffles = new cat();

IAnimal[] animals = new IAnimal[] {scruffy as IAnimal, ruffles as IAnimal} // gives null

o

IAnimal[] animals = new IAnimal[] {(IAnimal)scruffy, (IAnimal)ruffles} //throws exception

luego haz

foreach (IAnimal animal in animals)
{
   animal.eat();
}

¿Hay alguna manera de hacer que C # me permita tratar los volantes y desaliñados como un IAnimal sin tener que escribir: IAnimal al escribir la clase?

¡Gracias!

EDITAR (no perezoso): las clases se generan a partir de metadatos de proceso almacenados sql, lo que significa que cada vez que se genera, tendría que volver y agregarlos, o modificar el generador de código para identificar a los miembros que están en la interfaz, en realidad no es una mala idea. Esperaba que hubiera algún tipo de enfoque genérico o algo así.

¿Fue útil?

Solución

Puede resolver este problema con clases parciales : deje que el código generado / generado por la máquina esté en un archivo fuente de cada clase, y la parte codificada a mano (que define la subclase de IAnimal) en otro.

Otros consejos

Lo que está pidiendo se llama escribir pato y no es parte de C #, me temo. Cualquier solución implicará la reflexión y la observación de las propiedades. Creo que será más rápido comprobar las clases a mano, creo.

Sin embargo, sería un proyecto interesante intentarlo.

La solución es modificar el generador de código. Actualmente es demasiado simplista para sus necesidades. Debería agregar la implementación de la interfaz si las propiedades y / o métodos relevantes están presentes en la clase.

Puede crear un adaptador que acceda a " eat " a través de la reflexión, el pato de un hombre pobre escribiendo:

public class Adapter<T> : IAnimal
{
   private T x;

   Adapter(T x)
   {
     this.x = x;
   }

   public void eat()
   {
     x.GetType().GetMethod("eat").Invoke(this);
   }
}

Entonces puedes usarlo así:

dog scruffy = new dog();
cat ruffles = new cat();

IAnimal[] animals = new IAnimal[] {new Adapter<dog>(scruffy), new Adapter<cat>(ruffles )};

No es fácil que yo sepa, podría hacer una llamada de enlace tardío usando la reflexión, pero sería mejor que pase su tiempo editando las clases o escribiendo una macro para hacerlo.

Suponiendo que realmente no puede modificar la clase de gato por buenas razones,

Podría escribir un adaptador para cat que heredó de IAnimal, es decir:

  class cat_adapter : IAnimal
  {
       private cat baseCat;
       public cat_adapter( cat aCat)
       {
           baseCat = aCat;
       }

       // Implement IAnimal interface and redirect to baseCat
       public void eat()
       {
            baseCat.munchOnMeowMix();
       }

  }

En C ++ podría usar plantillas asumiendo que todas sus clases generadas necesitan tener la misma función llamada:

  template <class BaseType>
  class CAnimalAdapter : public IAnimal
  {
  private:
        BaseType* m_baseInstance;
  public:
        CAnimalAdapter(BaseType* baseInstance) :
            m_baseInstance(baseInstance)
        {
        }

        void eat()
        {
            // You will get a compiler error if BaseType doesn't have this implemented
            baseInstance->doEat();                
        }

  }

Tal vez alguien más C #py que yo pueda hacer lo mismo con la reflexión.

Si el generador de código genera las clases como parciales, puede agregar otra definición parcial que implemente la interfaz.

No. No hay forma de obtener C # que le permita hacer esto sin tener una clase base concreta o tener una interfaz.

Sus clases tienen que implementar la interfaz IAnimal. Un método / propiedad del mismo nombre en dos clases diferentes no se considera equivalente a menos que ambas sean implementaciones de una interfaz / clase base.

Si ya ha implementado el método y solo desea implementar la interfaz, puede usar una expresión regular con el comando replace in files en su IDE.

De lo contrario, eche un vistazo a los métodos de extensión. Pueden ajustarse a su necesidad.

Si implementa las clases generadas como clases parciales, podría implementar las interfaces en estas clases y luego cambiar su generador de código para generar solo la mitad de la clase parcial. Esto le permitiría regenerar sus clases sin perder la implementación de la interfaz (o cualquier otra lógica personalizada que decida agregar).

Este tipo de enfoque es cómo LINQ to SQL generaría archivos de clase.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top