Domanda

Ho 100 classi che hanno alcuni elementi simili e alcuni unici. Ho creato un'interfaccia che denomina elementi simili, ad esempio: interfaccia IAnimal. Quello che normalmente farei è:

class dog : IAnimal

Ma ci sono 100 lezioni e non ho voglia di seguirle tutte e cercare quelle a cui posso applicare IAnimal.

Quello che voglio fare è questo:

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

quindi

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

C'è un modo per fare in modo che C # mi permetta di trattare le increspature e trasandate come un IAnimal senza dover scrivere: IAnimal quando scrivo la classe.

Grazie!

EDIT (non pigro): le classi sono generate da metadati proc memorizzati sql, il che significa che ogni volta che viene generato dovrei tornare indietro e aggiungerli o modificare il generatore di codice per identificare i membri che sono in l'interfaccia, in realtà non è una cattiva idea. Speravo ci fosse una sorta di approccio generico o qualcosa del genere.

È stato utile?

Soluzione

Potresti risolvere questo problema con classi parziali : lascia che il codice generato / rigenerato dalla macchina sia in un file sorgente di ogni classe e la parte codificata a mano (che definisce la sottoclasse da IAnimal) in un'altra.

Altri suggerimenti

Quello che stai chiedendo si chiama Duck Typing e non fa parte di C # Temo. Qualunque soluzione comporterà la riflessione e l'esame delle proprietà. Penso che sarà più veloce controllare le lezioni a mano, credo.

Sarebbe comunque un progetto interessante da provare.

La soluzione è modificare il generatore di codice. Attualmente è troppo semplicistico per le tue esigenze. Dovrebbe aggiungere l'implementazione dell'interfaccia se le proprietà e / o i metodi rilevanti sono presenti nella classe.

Puoi creare un adattatore che acceda a " mangia " attraverso la riflessione, un'anatra di un povero digitando:

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

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

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

Quindi puoi usarlo in questo modo:

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

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

Non di cui sono a conoscenza, potresti fare una chiamata in ritardo con la riflessione ma sarebbe meglio passare il tempo a modificare le classi o scrivere una macro per farlo.

Supponendo che non sia possibile modificare la classe cat per buoni motivi,

Potresti scrivere un adattatore per cat ereditato da IAnimal, ovvero:

  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();
       }

  }

In C ++ puoi usare i template assumendo che tutte le tue classi generate debbano avere la stessa funzione chiamata:

  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();                
        }

  }

Forse qualcuno più C # -pia di me può fare lo stesso con la riflessione.

Se il generatore di codice genera le classi come parziali, è possibile aggiungere un'altra definizione parziale che implementa l'interfaccia.

No. Non è possibile ottenere C # per consentirti di farlo senza avere una classe base concreta o un'interfaccia.

Le tue classi devono implementare l'interfaccia IAnimal. Un metodo / proprietà con lo stesso nome su due classi diverse non sono considerati equivalenti a meno che non siano entrambe implementazioni di una classe interfaccia / base.

Se hai già implementato il metodo e desideri solo implementare l'interfaccia, puoi utilizzare un'espressione regolare con il comando Sostituisci nei file nel tuo IDE.

Altrimenti, dai un'occhiata ai metodi di estensione. Potrebbero soddisfare le tue necessità.

Se si implementano le classi generate come classi parziali, è possibile implementare le interfacce su queste classi e quindi modificare il generatore di codice per generare solo metà della classe parziale. Ciò ti consentirebbe di rigenerare le tue classi senza perdere l'implementazione dell'interfaccia (o qualsiasi altra logica personalizzata che decidi di aggiungere).

Questo tipo di approccio è il modo in cui LINQ to SQL genererebbe i file di classe.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top