Clases parciales en C#
Esta vez toca hablar de otra de las características de C# (y de .NET en general). Esta vez son las clases parciales.
Tal vez alguna vez te hayas encontrado con que, en la declaración de una clase, la palabra partial
está antepuesta a la palabra class
. Pero, ¿qué significa esto?
Que una clase esté marcada como partial
o parcial, significa que la definición de esta puede estar distribuida en más de un bloque de código. Por ejemplo, mira la definición completa de la clase Program
:
namespace Parciales
{
// Block 1
partial class Program
{
public static void Main(string[] args)
{
Write(HelloWorldString);
}
}
// Class constants. Block 2
partial class Program
{
private const string HelloWorldString = "Hola mundo!";
}
}
En este caso, la clase está declarada en dos bloques.
Esto parece no muy útil, ¿cierto? sin embargo, la ventaja de las clases parciales es que nos permite separar la definición de una clase a través de varios archivos, por ejemplo, podríamos tener el archivo Program.cs y el archivo ProgramMethods.cs para separar la programación de la clase. En el ejemplo anterior, el método Write
está definido en otro archivo, que contiene otra definición parcial de la clase:
partial class Program
{
public static void Write(string line)
{
Console.WriteLine(line);
}
}
Cuando llega el momento de compilar, el compilador tomará todas las definiciones parciales de una clase y la convertirá en una sola, es por eso que si escribimos la misma firma de método o nombre de propiedad en dos archivos diferentes obtendremos un error de compilación.
Y... eso es todo lo que necesitas saber sobre clases parciales.
¡NO! aguarda, aún hay más. La posibilidad de dividir la definición de una clase en múltiples archivos es una de las más criticadas, ya que usada sin cuidado puede transformar tu código (y los archivos en los que está definido) en un verdadero laberinto. Es por eso que hay ciertos escenarios en los que su uso es recomendado y fuera de ellos su uso debería ser restringido.
Veamos algunos de los usos comunes:
Definición de interfaz gráfica
Si has trabajado con tecnologías como Windows Forms, Web Forms, y más reciente, Xamarin Forms, tal vez te hayas dado cuenta que junto a la definición de la interfaz gráfica (un archivo .aspx o .xaml) se genera automáticamente un archivo que contiene una clase parcial en donde están declarados los controles que definiste en la pantalla. A su vez existe otro archivo en el que tu puedes escribir la lógica de tu aplicación.
Es decir, existe un archivo para la interfaz y otro para la lógica, esto resulta bastante útil ya que nos evita correr el riesgo de modificar el código que define la interfaz y nos quita de la vista código que realmente nosotros nunca escribimos por nuestra cuenta.
Aún recuerdo cuando usé NetBeans con Java Swing. Seguramente también recuerdas ese bloque enorme de código que no puedes modificar... ewww
Por ejemplo, mira estas clases, tal vez re recuerden algo:
Lógica
public partial class Page
{
public Page()
{
InitializeComponent();
Console.WriteLine(Control1);
Console.WriteLine(Control2);
Console.WriteLine(Control3);
}
}
Código generado
// This code was generated by a tool,
// any changes made to this file will be discarded
public partial class Page
{
object Control1;
object Control2;
object Control3;
void InitializeComponent()
{
// ...code
}
}
Reutilizar código
Otro buen uso surgió junto con los shared projects, y es que con ellos podemos concentrar el código que se puede compartir en un solo archivo y dejar las implementaciones específicas para cada plataforma. el de abajo es un ejemplo muy burdo, pero te puede dar una idea:
Core.cs en el proyecto compartido
public partial class Core
{
public Core()
{
#if __ANDROID/
int camera = 0;
string options = "";
var photo = TakePhoto(camera, options);
#elif __IOS/
string camera = "";
var photo = TakePhoto(camera);
#endif
int byteCount = photo.Length;
}
}
CoreAndroid.cs en el proyecto de Android
public partial class Core
{
byte[] TakePhoto(int camera, string options)
{
return new byte[0];
}
}
CoreiOS.cs en el proyecto de iOS
public partial class Core
{
byte[] TakePhoto(string camera)
{
return new byte[0];
}
}
Trabajo en equipo
Con anterioridad se recomendaba que si varios programadores trabajaban en una clase, esta se dividiera en varios archivos para hacer más sencillo el trabajo a la hora de juntar los cambios, actualmente podemos usar con más seguridad algún sistema de control de versiones para la misma tarea.
"Simplificar" el código
Eh, pues simplemente eso, "simplificar" una clase larga para facilitar su lectura. En realidad, creo que si tienes una clase muy grande, antes de considerar separarla en varios archivos, debes considerar repasar tu diseño de aplicación y separar tu clase en varias clases. Si después de pensarlo, usar clases parciales sigue siendo la única opción, pues lo puedes hacer.
Lo que sigue
No olvides que puedes descargar el código fuente para que hagas pruebas con él.
Volviendo a las clases parciales, los mejores casos de uso son para herramientas que generan código o para maximizar la cantidad de código compartido, fuera de esos escenarios, su uso es bastante criticado ya que, si abusas de ellas, el código se puede tornar confuso al estar distrinuído en distintos archivos. Como siempre, nunca está de más conocer otra herramienta para cuando llega el momento de programar.