sábado, 22 de enero de 2011

Clases y métodos parciales

Una clase parcial permite dividir la definición de una clase en múltiples ficheros.
Después y en tiempo de compilación, los distintos ficheros en los que está definida la clase se unirán para formar una sola clase igual que si se hubiera definido inicialmente en un solo fichero.

La magia de combinar distintos ficheros de una misma clase se consigue a través de la palabra clave Partial (en realidad, no hace falta que cada definición parcial de la clase esté en un fichero distinto).

Lo cierto es que Visual Studio es bastante flexible con la definición de clases parciales y podemos ver cualquiera de los siguientes escenarios:

  • Un solo fichero con una sola clase con la palabra Partial (es decir, no es parcial pero aunque se indique no hay ningún error).
  • Dos ficheros con dos clases, ambas con la palabra clave Partial.
  • Dos ficheros con dos clases y sólo una de ellas con la palabra clave Partial.

Por otro lado, los métodos parciales son métodos donde su firma o prototipo está declarado en un fichero y su implementación está en otro fichero.

De nuevo y en tiempo de compilación, para aquellos métodos parciales para los que no se ha escrito una implementación, el compilador eliminará tanto el prototipo o firma del método, como todas las llamadas al mismo en nuestro código.

Un método parcial cumple las siguientes características:

  • Sólo se pueden declarar en clases parciales
  • Sólo pueden ser procedimientos (Sub)
  • Su ámbito tiene que ser privado
  • Sólo se usa la palabra Partial en el prototipo.
  • Los nombres de la implementación deben coincidir con los parámetros del prototipo.

Los usos más habituales de las clases parciales son:

  • Mejorar la legibilidad de clases muy grandes al separar la clase en varios ficheros.
  • Si se está trabajando con un software de control de código fuente, al separar la clase en varios ficheros se permite que varios desarrolladores trabajen en la misma clase y así evitar conflictos con la protección y desprotección de un solo fichero.
  • Con código auto-generado, el desarrollador puede escribir código personalizado para extender una clase en un fichero aparte con la seguridad de que no será machacado posteriormente si se vuelve a autogenerar el código.
  • También es posible separar conceptualmente los métodos de una clase (como si fueran regiones) o decidir que cuando se implementa una interfaz, ésta se implementa en un fichero aparte.

Por supuesto, y antes de que el ávido lector lo pregunte, una clase parcial no puede estar escrita en distintos lenguajes ni puede estar definida en distintos ensamblados, por lo que no se puede “anexar” una clase parcial a una clase de un ensamblado de terceros (para extender este tipo de clases podríamos utilizar los métodos extensores, pero esto será en otro post, que ya está escrito!)

Un error que suele suceder cuando hablamos de métodos parciales, es que se confunde un método parcial con un evento, y aunque tiene un parecido razonable, hay diferencias entre ellos que nos enseñan que no son conceptos intercambiables.

  • Un método parcial tiene que ser implementado en la propia clase, mientras que la suscripción a un evento puede ser realiza en cualquier clase.
  • La suscripción a un evento sucede siempre en tiempo de ejecución (siendo además posible anular esa suscripción, por ejemplo con RemoveHandler), mientras que con un método parcial el enlace es siempre en tiempo de compilación.
  • Un evento permite múltiples suscripciones y múltiples suscriptores.
  • Un evento permite distintos ámbitos de visibilidad (público, privado, etc.) mientras que un método parcial es siempre privado.

Hay que entender un método parcial como una “oportunidad” que, normalmente un código auto-generado, nos ofrece para personalizar su comportamiento. Con esto quiero decir que fuera del contexto de código autogenerado, un método parcial no parece tener mucho sentido (sobre todo porque el ámbito del método tiene que ser privado, así que un cliente de nuestra clase no podría hacer nada con este método).

No me gustaría finalizar este post sin algunos ejemplos que ilustrarán el uso de lo aquí expuesto:

' Clase parcial

Partial Public Class Persona

    Property Nombre As String

 

    Public Sub Saludar(ByVal saludo As String)

        ' Llamada a un método parcial

        ' Si durante la compilación, VS no encuentra una implementación

        '  para el método PrevioSaludar elíminará ésta llamada a PrevioSaludar

        PrevioSaludar(saludo)

        ' Fijarse que la propiedad Apellidos está en otro fichero

        Console.WriteLine(String.Format("Saludos {0} {1}", Nombre, Apellidos))

    End Sub

 

    ' Prototipo del método parcial PrevioSaludar

    ' NO puede tener código, sólo la firma

    Partial Private Sub PrevioSaludar(ByVal saludo As String)

    End Sub

 

End Class

 

' Clase parcial

Partial Class Persona

    Property Apellidos As String

End Class

 

Si ejecutamos ahora el siguiente código (y puesto que no hemos implementado el método parcial), la salida será la siguiente::

    Sub Main()

        Dim yo As New Persona With {.Nombre = "Sergio", .Apellidos = "León"}       

        yo.Saludar("Hola Mundo!")

        Console.ReadLine()

    End Sub

 

 

clip_image001

 

Sin embargo, si ahora implementamos el método parcial, tendremos ésta otra salida:

' Clase parcial

Partial Class Persona

    Property Apellidos As String

 

    ' Implementación de un método parcial

    ' Fijarse que NO lleva la palabra Partial

    ' Además, el nombre de los parámetros es igual que el prototipo

    Private Sub PrevioSaludar(ByVal saludo As String)

        Console.WriteLine(String.Format("Saludo parcial {0}", saludo))

    End Sub

End Class

 

clip_image002

Donde podemos ver que se ha llamado a la implementación del método parcial.

Un saludo!

No hay comentarios:

Publicar un comentario