2010-10-29 11 views
15

Supponiamo che tu abbia due diverse classi C# A e B che mentre non derivano dalla stessa classe base condividono alcuni degli stessi nomi per i metodi. Ad esempio, entrambe le classi hanno un metodo connect e un metodo disconnect e molti altri. Voglio essere in grado di scrivere codice una volta che funzionerà con entrambi i tipi.Codice C# per gestire classi diverse con gli stessi nomi di metodo

Ecco un esempio semplificato di quello che vorrei fare:

public void make_connection(Object x) 
{ 
    x.connect() ; 
    // Do some more stuff... 
    x.disconnect() ; 
    return ; 
} 

Naturalmente, questo non compila la classe Object non ha un metodo connect o disconnect.

C'è un modo per farlo?

AGGIORNAMENTO. Avrei dovuto chiarirlo fin dall'inizio: ho solo le DLL per A e B e non la fonte.

+5

Questo è più o meno come tutti imparano quanto sia prezioso il costrutto interfaccia è. Hai davvero bisogno di colpire una situazione in cui sono utili prima di "ottenerlo". –

risposta

26

È possibile utilizzare un'interfaccia per compiere ciò che si vuole fare.

interface IConnectable 
{ 
    void Connect(); 

    void Disconnect(); 
} 

Sia A e B dovrebbe implementare IConnectable. Quindi utilizzare IConnectable anziché Object come tipo di parametro per il metodo e si dovrebbe essere tutto impostato.

public void MakeConnection(IConnectable connectable) 
{ 
    connectable.Connect(); 

    // Do some more stuff... 

    connectable.Disconnect(); 
} 

Edit: Dal momento che non hai il codice sorgente, si dispone di un paio di opzioni:

  1. soluzione Usa Max di utilizzare la parola chiave dynamic, (se si utilizza .NET 4.0) La soluzione di
  2. Uso Steve di utilizzare casting e if/else dichiarazioni
  3. creare classi wrapper per A e B e hanno li implementano l'interfaccia (o uso comune classe di base astratta per loro)

Ad esempio:

class AWrapper : IConnectable 
{ 
    private A obj; 

    public AWrapper(A obj) 
    { 
     this.obj = obj; 
    } 

    public void Connect() 
    { 
     this.obj.Connect(); 
    } 

    public void Disconnect() 
    { 
     this.obj.Disconnect(); 
    } 

    // other methods as necessary 
} 

(BWrapper sarebbe simile, usando solo B invece di A)

Poi si potrebbe creare i wrapper e passarli in MakeConnection. Spetta a te come lo vuoi fare. A seconda della situazione, un metodo potrebbe essere più semplice degli altri.

+3

Essere pedantici qui, ma le classi non * ereditano * le interfacce, esse * le implementano *. – Phil

+0

@Phil: Grazie! Fisso. –

+2

Come si fa A e B a implementare un'interfaccia se non si ha il codice sorgente su A e B? – rlandster

2

Provare a utilizzare piuttosto un'interfaccia.

Dai un'occhiata alla interface (C# Reference) e Interfaces (C# Programming Guide)

Quindi qualcosa di simile

public interface IConnections 
{ 
    void connect(); 
    void disconnect(); 
} 

public class A : IConnections 
{ 
    public void connect() 
    { 
     //do something 
    } 

    public void disconnect() 
    { 
     //do something 
    } 
} 

public class B : IConnections 
{ 
    public void connect() 
    { 
     //do something 
    } 

    public void disconnect() 
    { 
     //do something 
    } 
} 

public void make_connection(IConnections x) 
{ 
    x.connect(); 
    // Do some more stuff... 
    x.disconnect(); 
    return; 
} 
1

C'è un concetto OOAD di 'Programe a un'interfaccia non un'implementazione' che ti permette di evitare la catena di ereditarietà gerarchie

1- È possibile creare un interfcae

interface IConnection 
{ 
    void Connect(); 
    void Disconnect(); 
} 

2 - E lascia che le tue classi implementino questa interfaccia come mostrato di seguito.

class A : IConnection 
{ 
    #region IConnection Members 

    public void Connect() 
    { 
     // your connect method implementation goes here. 
    } 

    public void Disconnect() 
    { 
     // your disconnect method implementation goes here. 
    } 

    #endregion 
} 


class B : IConnection 
{ 
    #region IConnection Members 

    public void Connect() 
    { 
     // your connect method implementation goes here. 
    } 

    public void Disconnect() 
    { 
     // your disconnect method implementation goes here. 
    } 

    #endregion 
} 

3- Una volta finito con l'attuazione di quanto si può rendere la vostra funzione di accettare un argomento di IConnection come illustrato di seguito.

public void makeConnection(IConnection con) 
    { 
     con.Connect(); 
     con.Disconnect(); 
    } 

4- E dal codice client, è possibile passare l'oggetto delle classi che implementa IConnect Interface.

0

O si dovrà utilizzare un'interfaccia (o classe base), come mostrato da Zach e Astander, o si dovrà caso l'oggetto prima di utilizzare:

public void make_connection(Object x) 
{ 
    ((A)x).connect() ; 
    // Do some more stuff... 
    x.disconnect() ; 
    return ; 
} 
1

Se la soluzione di interfaccia non è possibile (es. non hai il codice sorgente), un'altra soluzione meno efficiente è usare la riflessione.

+0

+1 per ulteriore soluzione da utilizzare nel caso in cui l'approccio standard (interfaccia) non possa essere eseguito. – VitalyB

12

Ciò funzionerà in C# 4:

public void make_connection(dynamic x) 
{ 
    x.connect() ; 
    // Do some more stuff... 
    x.disconnect() ; 
    return ; 
} 
+2

+1 per essere più typesafe potresti avere metodi pubblici fortemente tipizzati - 'make_connection (A a)' - che delegano ad un metodo dinamico privato. –

0

Si potrebbe anche usare la reflection per richiamare i metodi

1

Come altri hanno detto, re-factoring per utilizzare le interfacce o utilizzando l'approccio dinamico sono probabilmente il modi più eleganti.

Se ciò non è possibile, è possibile trasmettere l'oggetto ai tipi. Ti suggerirei di utilizzare as e quindi controllare che il cast funzionasse, un cast non controllato sarebbe pericoloso se qualcuno lo chiamasse con un tipo che non è riuscito a trasmettere.

E.g. Se tipi A e B entrambi hanno un metodo chiamato DoSomething() allora questo lavoro ...

public static void CallDoSomething(object o) 
    { 
     A aObject = o as A; 

     if (aObject != null) 
     { 
      aObject.DoSomething(); 
      return; 
     } 

     B bObject = o as B; 

     if (bObject != null) 
     { 
      bObject.DoSomething(); 
      return; 
     } 
    } 

MA questo è abbastanza brutto per essere onesti ... mi piacerebbe molto provare e refactoring alle interfacce.

0

Quello che vuoi si chiama Duck Typing.

Da Wikipedia:

anatra scrivendo è uno stile di tipizzazione dinamica in cui la corrente set di un oggetto di metodi e proprietà determina la semantica vigenti, piuttosto che la sua eredità da una particolare classe o attuazione di un interfaccia specifica.

C# 4.0 permette questo, come altri hanno già detto, utilizzando il dinamica parola chiave

Problemi correlati