Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

17 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
miércoles, 2 de abril de 2008
Piezas de puzzleAunque las clases parciales aparecieron hace unos años, con la llegada de .Net 2.0 y Visual Studio 2005, vamos a hacer un breve repaso como preparación para un próximo post que trate los métodos parciales.

Las clases parciales (llamados también tipos parciales) son una característica presente en algunos lenguajes de programación, como C# y VB.Net, que permiten que la declaración de una clase se realice en varios archivos de código fuente, rompiendo así la tradicional regla "una clase, un archivo". Será tarea del compilador tomar las porciones de los distintos archivos y fundirlas en una única entidad.

En VB.Net y C#, a diferencia de otros lenguajes, es necesario indicar explícitamente que una clase es parcial, es decir, que es posible que haya otros archivos donde se continúe la declaración de la misma, usando en ambos con la palabra clave partial en la definición del tipo:
  ' VB.NET 
Public Partial Class Persona
...
End Class

// C#
public partial class Persona
{
...
}
 
En este código hemos visto cómo se declara una clase parcial en ambos lenguajes, que es prácticamente idéntica salvo por los detalles sintácticos obvios. Por ello, a partir de este momento continuaré introduciendo los ejemplos sólo en C#.

Pero antes un inciso: la única diferencia entre ambos, estrictamente hablando, es que C# obliga a que todas las apariciones de la clase estén marcadas como parciales, mientras que en VB.Net puede dejarse una de ellas (llamémosla "declaración principal") sin indicar que es parcial, y especificarlo en el resto de apariciones. En mi opinión, esta no es una práctica recomendable, por lo que aconsejaría utilizar el modificador partial siempre que la clase lo sea, e independientemente del lenguaje utilizado, pues contribuirá a la mantenibilidad del código.

El número de partes en las que se divide una clase es indiferente, el compilador tomará todas ellas y generará en el ensamblado como si fuera una clase normal.

Para comprobarlo he creado un pequeño código con dos clases exactamente iguales, salvo en su nombre. Una de ellas se denomina PersonaTotal, y está definida como siempre, en un único archivo; la otra, PersonaParcial, es parcial y la he troceado en tres archivos, como sigue:
  // *** Archivo PersonaParcial.Propiedades.cs ***
// Aquí definiremos todas las propiedades

partial class PersonaParcial
{
public string Nombre { get; set; }
public string Apellidos { get; set; }
}

// *** Archivo PersonaParcial.IEnumerable.cs ***
// Aquí implementaremos el interfaz IEnumerable

partial class PersonaParcial: IEnumerable
{
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
}

// *** Archivo PersonaParcial.Metodos.cs ***
// Aquí implementaremos los métodos que necesitemos

partial class PersonaParcial
{
public override string ToString()
{
return Nombre + " " + Apellidos;
}
}
 
Y efectivamente, el resultado de compilar ambas clases, según se puede observar con ILDASM es idéntico:

Clases generadas tras la compilación

A la hora de crear clases parciales es conveniente tener los siguientes aspectos en cuenta:
  • Los atributos de la clase resultante serán la combinación de los atributos definidos en cada una de las partes.
  • El tipo base de los distintos fragmentos debe ser el mismo, o aparecer sólo en una de las declaraciones parciales.
  • Si se trata de una clase genérica, los parámetros deben coincidir en todas las partes.
  • Los interfaces que implemente la clase resultante será la unión de todos los implementados por las distintas secciones.
  • De la misma forma, los miembros (métodos, propiedades, campos...) de la clase final será la unión de todos los definidos en las distintas partes.

Vale, ya hemos visto qué son y cómo se usan, pero, ¿para qué sirven? ¿cuándo es conveniente utilizarlas? Pues bien, son varios los motivos de su existencia, algunos discutibles y otros realmente interesantes.

En primer lugar, no era sencillo que varios desarrolladores trabajaran sobre una misma clase de forma concurrente. Incluso utilizando sistemas de control de versiones (como Sourcesafe o Subversion), la unidad mínima de trabajo es el archivo de código fuente, y la edición simultánea podía generar problemas a la hora de realizar fusiones de las porciones modificadas por cada usuario.

En segundo lugar, permite que clases realmente extensas puedan ser troceadas para facilitar su comprensión y mantenimiento. Igualmente, puede utilizarse para separar código en base a distintos criterios:
  • por ejemplo, separar la interfaz (los miembros visibles desde el exterior de la clase) y por otra los miembros privados a la misma
  • o bien separar las porciones que implementan interfaces, o sobreescriben miembros de clases antecesoras de los pertenecientes a la propia clase
  • o separar temas concernientes a distintos dominios o aspectos
En tercer lugar, aunque da la impresión que fue el motivo más importante para decidir su inclusión, las clases parciales permiten utilizar de forma efectiva herramientas automáticas de generación de código.

Así, es posible que un desarrollador y un generador estén introduciendo cambios sobre la misma clase sin molestarse, cada uno jugando con su propia porción de la clase; el primero puede introducir funcionalidades sin preocuparse de que una nueva generación automática de código pueda machacar su trabajo. Visual Studio y otros entornos de desarrollo hacen uso intensivo de esta capacidad, por ejemplo, en los diseñadores visuales de Windows Forms, WPF, ASP.Net e incluso el generador de modelos de LinqToSql.

Publicado en: http://www.variablenotfound.com/.

Aún no hay comentarios, ¡sé el primero!