2010-10-29 10 views
15

Digamos que tiene dos clases diferentes de C# A y B que aunque no se derivan de la misma clase base, comparten algunos de los mismos nombres para los métodos. Por ejemplo, ambas clases tienen un método connect y disconnect, así como varios otros. Quiero poder escribir código una vez que funcione con ambos tipos.Código C# para manejar diferentes clases con los mismos nombres de método

Aquí es un ejemplo simplificado de lo que me gustaría hacer:

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

Por supuesto, esto no se compila como la clase de objeto no tiene un método connect o disconnect.

¿Hay alguna manera de hacerlo?

ACTUALIZACIÓN. Debería haberlo aclarado desde el principio: solo tengo las DLL para A y B y no la fuente.

+5

Esto es más o menos como todo el mundo aprende lo valioso que es la construcción de la interfaz. Realmente necesita llegar a una situación en la que sea útil antes de "obtenerla". –

Respuesta

26

Se puede utilizar una interfaz para lograr lo que quiere hacer.

interface IConnectable 
{ 
    void Connect(); 

    void Disconnect(); 
} 

Tanto A y B deberían aplicar IConnectable. Luego use IConnectable en lugar de Object como el tipo de parámetro para su método y debe estar todo listo.

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

    // Do some more stuff... 

    connectable.Disconnect(); 
} 

Editar: Puesto que usted no tiene el código fuente, usted tiene un par de opciones:

  1. solución de uso máximo de la utilización de la palabra clave dynamic, (si está utilizando .NET 4.0) solución de utilizar la fundición y if/else declaraciones
  2. crear clases contenedoras para A y B y tienen de
  3. uso Steve a implementar la interfaz (o utilizar la clase base abstracta común para ellos)

Por ejemplo:

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 serían similares, simplemente usando B en lugar de A)

Posteriormente, se podría crea las envolturas y pásalas al MakeConnection. Depende de usted cómo quiera hacerlo. Dependiendo de su situación, un método puede ser más fácil que los demás.

+3

Ser pedante aquí, pero las clases no heredan * interfaces, sino que las implementan *. – Phil

+0

@Phil: ¡Gracias! Fijo. –

+2

¿Cómo se hace para que A y B implementen una interfaz si no tienes el código fuente para A y B? – rlandster

2

Pruebe usar una interfaz.

Tenga una mirada en interface (C# Reference) y Interfaces (C# Programming Guide)

así que algo como

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

Hay un concepto OOAD de 'Programe a una interfaz no a una aplicación', que te permite evitar la cadena de herencia jerarquías

1- Se puede crear un interfcae

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

2 - Y permita que sus clases implementen esta interfaz como se muestra a continuación.

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 vez que haya terminado con la aplicación de lo que puede hacer su función de aceptar un argumento de IConnection como se muestra a continuación.

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

4- Y desde su código de cliente, puede pasar el objeto de las clases que implementa IConnect Interface.

0

O se tendrá que utilizar una interfaz (o clase base), como se muestra por Zach y Astander, o tendrá que caso el objeto antes de usar:

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

Si la solución de interfaz no es posible (por ejemplo, no tiene el código fuente), otra solución menos eficiente es usar la reflexión.

+0

+1 para solución adicional que se utilizará en caso de que el enfoque estándar (interfaz) no se pueda realizar. – VitalyB

12

Esto funcionará en C# 4:

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

+1 para ser más seguro, podría tener métodos públicos fuertemente tipados - 'make_connection (A a)' - que deleguen a un método dinámico privado. –

0

También se puede utilizar la reflexión para invocar los métodos

1

Como otros han dicho, re-factoring para usar interfaces o utilizando el enfoque dinámico son probablemente las maneras más elegantes.

Si esto no es posible, puede convertir el objeto a sus tipos. Sugiero usar as y luego verificar que el yeso funcionó, un lanzamiento no verificado sería peligroso si alguien lo llama con un tipo que no se pudo lanzar.

E.g. Si los tipos A y B ambos tienen un método llamado DoSomething() entonces esto va a funcionar ...

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

pero esto es bastante fea para ser honesto ... yo realmente trato de refactorizar a las interfaces.

0

Lo que quiere se llama Duck Typing.

De Wikipedia:

pato escribiendo es un estilo de tipado dinámico en el que conjunto actual de un objeto de métodos y propiedades determina la semántica válidos, en lugar de su herencia de una clase particular o la implementación de un interfaz específica.

C# 4.0 permite esto, como otros han dicho, el uso de la palabra clave dinámica

Cuestiones relacionadas