CSharp

Tutorial CSharp: Miembros estáticos

Aprende sobre miembros estáticos en C#: campos, propiedades, métodos y clases estáticas con ejemplos prácticos y casos de uso comunes.

Aprende CSharp y certifícate

Campos y propiedades static

En C#, los miembros estáticos (static) pertenecen a la clase en sí misma y no a instancias específicas de esa clase. Esto significa que existe una única copia de estos miembros que es compartida por todas las instancias de la clase, o incluso accesible sin necesidad de crear ninguna instancia.

Los campos y propiedades estáticos son especialmente útiles cuando necesitamos almacenar información que debe ser común a todos los objetos de una clase, o cuando queremos mantener datos que existan independientemente de cualquier instancia.

Campos estáticos

Un campo estático se declara utilizando la palabra clave static antes del tipo de dato. Veamos un ejemplo básico:

public class Contador
{
    // Campo estático
    public static int NumeroDeInstancias = 0;
    
    // Constructor
    public Contador()
    {
        // Incrementamos el contador cada vez que se crea una instancia
        NumeroDeInstancias++;
    }
}

En este ejemplo, NumeroDeInstancias es un campo estático que lleva la cuenta de cuántas instancias de la clase Contador se han creado. Cada vez que se crea un nuevo objeto, el constructor incrementa este contador.

Para acceder a un campo estático, utilizamos el nombre de la clase seguido por un punto y el nombre del campo:

// Crear algunas instancias
Contador c1 = new Contador();
Contador c2 = new Contador();
Contador c3 = new Contador();

// Acceder al campo estático
Console.WriteLine($"Se han creado {Contador.NumeroDeInstancias} instancias"); // Mostrará "Se han creado 3 instancias"

Observa que accedemos al campo estático a través del nombre de la clase (Contador.NumeroDeInstancias) y no a través de una instancia específica.

Propiedades estáticas

De manera similar a los campos, también podemos crear propiedades estáticas. Las propiedades nos permiten controlar el acceso a los campos mediante getters y setters:

public class Configuracion
{
    // Campo estático privado
    private static string _nombreAplicacion = "Mi Aplicación";
    
    // Propiedad estática
    public static string NombreAplicacion
    {
        get { return _nombreAplicacion; }
        set { _nombreAplicacion = value; }
    }
    
    // Propiedad estática de solo lectura (con sintaxis de expresión)
    public static string Version => "1.0.0";
}

En este ejemplo, NombreAplicacion es una propiedad estática que permite leer y modificar el campo privado _nombreAplicacion. También hemos definido una propiedad de solo lectura Version utilizando la sintaxis de expresión (=>).

Para acceder a estas propiedades:

// Leer una propiedad estática
Console.WriteLine($"Nombre: {Configuracion.NombreAplicacion}"); // Muestra "Nombre: Mi Aplicación"
Console.WriteLine($"Versión: {Configuracion.Version}"); // Muestra "Versión: 1.0.0"

// Modificar una propiedad estática
Configuracion.NombreAplicacion = "Nueva Aplicación";
Console.WriteLine($"Nuevo nombre: {Configuracion.NombreAplicacion}"); // Muestra "Nuevo nombre: Nueva Aplicación"

Inicialización de campos estáticos

Los campos estáticos se inicializan antes de que se cree cualquier instancia de la clase. Podemos inicializarlos de varias formas:

  • Inicialización directa: Como vimos en los ejemplos anteriores.
  • Inicializador estático: Un bloque de código que se ejecuta una sola vez cuando la clase se carga en memoria.
public class Utilidades
{
    // Campo estático
    public static double PI;
    
    // Inicializador estático
    static Utilidades()
    {
        PI = 3.14159265359;
        Console.WriteLine("La clase Utilidades ha sido inicializada");
    }
}

El inicializador estático (también llamado constructor estático) se ejecuta automáticamente antes de que se acceda por primera vez a cualquier miembro estático de la clase.

Casos de uso comunes

Los campos y propiedades estáticos son útiles en varios escenarios:

  • Constantes y valores de configuración: Valores que deben ser accesibles globalmente.
public class Constantes
{
    public static readonly int TamañoMaximoArchivo = 10485760; // 10 MB
    public static readonly string[] ExtensionesPermitidas = { ".jpg", ".png", ".gif" };
}
  • Contadores y estadísticas: Para llevar un registro de información global.
public class BaseDatos
{
    public static int NumeroConexiones = 0;
    public static int ConsultasRealizadas = 0;
    
    public void Conectar()
    {
        NumeroConexiones++;
        // Código para conectar a la base de datos
    }
    
    public void EjecutarConsulta(string consulta)
    {
        ConsultasRealizadas++;
        // Código para ejecutar la consulta
    }
}
  • Caché de datos: Para almacenar información que debe ser compartida entre todas las instancias.
public class CacheUsuarios
{
    // Diccionario estático para almacenar usuarios por ID
    private static Dictionary<int, string> _usuarios = new Dictionary<int, string>();
    
    // Método para agregar un usuario al caché
    public static void AgregarUsuario(int id, string nombre)
    {
        _usuarios[id] = nombre;
    }
    
    // Método para obtener un usuario del caché
    public static string ObtenerUsuario(int id)
    {
        if (_usuarios.ContainsKey(id))
            return _usuarios[id];
        return "Usuario no encontrado";
    }
}

Consideraciones importantes

Al trabajar con campos y propiedades estáticos, debemos tener en cuenta algunas consideraciones:

  • No dependen de instancias: Los miembros estáticos existen independientemente de las instancias de la clase.
  • Memoria compartida: Todos los objetos comparten la misma copia de los campos estáticos.
  • Duración: Los campos estáticos existen durante toda la vida de la aplicación.
  • Acceso concurrente: En aplicaciones multihilo, debemos tener cuidado con el acceso concurrente a los campos estáticos.
public class Ejemplo
{
    // Campo estático seguro para múltiples hilos
    private static readonly object _bloqueo = new object();
    private static int _contador = 0;
    
    public static void IncrementarContador()
    {
        lock (_bloqueo)
        {
            _contador++;
        }
    }
    
    public static int ObtenerContador()
    {
        return _contador;
    }
}

En este ejemplo, utilizamos un objeto de bloqueo (_bloqueo) para garantizar que solo un hilo a la vez pueda modificar el contador, evitando así posibles problemas de concurrencia.

Ejemplo práctico: Utilidad matemática

Veamos un ejemplo más completo de una clase de utilidad matemática que utiliza campos y propiedades estáticos:

public class MatematicaUtil
{
    // Constantes matemáticas como campos estáticos de solo lectura
    public static readonly double PI = 3.14159265359;
    public static readonly double E = 2.71828182846;
    
    // Propiedad estática para configuración
    private static int _precision = 2;
    public static int Precision
    {
        get { return _precision; }
        set { _precision = value > 0 ? value : 2; }
    }
    
    // Método estático que utiliza la propiedad Precision
    public static double Redondear(double valor)
    {
        double factor = Math.Pow(10, Precision);
        return Math.Round(valor * factor) / factor;
    }
    
    // Método estático para calcular el área de un círculo
    public static double AreaCirculo(double radio)
    {
        double area = PI * radio * radio;
        return Redondear(area);
    }
}

Y así podríamos utilizarla:

// Usar los campos estáticos
Console.WriteLine($"El valor de PI es: {MatematicaUtil.PI}");

// Usar la propiedad estática
MatematicaUtil.Precision = 4;

// Usar los métodos estáticos
double area = MatematicaUtil.AreaCirculo(5);
Console.WriteLine($"El área de un círculo de radio 5 es: {area}");

Este ejemplo muestra cómo los campos y propiedades estáticos pueden ser útiles para crear clases de utilidad que proporcionan funcionalidad sin necesidad de crear instancias.

Métodos estáticos

Los métodos estáticos en C# son métodos que pertenecen a la clase en lugar de a instancias específicas. Al igual que los campos y propiedades estáticas, estos métodos se pueden invocar directamente desde la clase sin necesidad de crear un objeto.

Un método estático se declara utilizando la palabra clave static en su definición. Estos métodos son particularmente útiles para operaciones que no dependen del estado de un objeto específico, como funciones de utilidad o cálculos independientes.

Declaración de métodos estáticos

La sintaxis para declarar un método estático es sencilla:

public class Calculadora
{
    public static int Sumar(int a, int b)
    {
        return a + b;
    }
}

En este ejemplo, Sumar es un método estático que acepta dos parámetros enteros y devuelve su suma. Para llamar a este método, no necesitamos crear una instancia de la clase Calculadora:

// Llamada a un método estático
int resultado = Calculadora.Sumar(5, 3);
Console.WriteLine($"La suma es: {resultado}"); // Muestra "La suma es: 8"

Características importantes de los métodos estáticos

Los métodos estáticos tienen varias características que debemos tener en cuenta:

  • No pueden acceder a miembros no estáticos de la clase directamente.
  • No pueden usar la palabra clave this, ya que no operan sobre una instancia.
  • Pueden acceder solo a otros miembros estáticos de la clase.
public class Ejemplo
{
    // Campo no estático
    private int _contador = 0;
    
    // Campo estático
    private static string _nombre = "Ejemplo";
    
    // Método estático
    public static void MostrarNombre()
    {
        Console.WriteLine(_nombre); // Correcto: accede a campo estático
        
        // Error: no puede acceder a _contador porque no es estático
        // Console.WriteLine(_contador);
        
        // Error: no puede usar 'this' en un contexto estático
        // Console.WriteLine(this._nombre);
    }
    
    // Método no estático
    public void IncrementarContador()
    {
        _contador++; // Correcto: accede a campo no estático
        Console.WriteLine(_nombre); // También puede acceder a campos estáticos
    }
}

Casos de uso comunes

Los métodos estáticos son ideales para varios escenarios:

  • Funciones de utilidad: Operaciones que no requieren estado de instancia.
public class StringUtil
{
    public static string InvertirTexto(string texto)
    {
        char[] caracteres = texto.ToCharArray();
        Array.Reverse(caracteres);
        return new string(caracteres);
    }
    
    public static bool EsPalindromo(string texto)
    {
        string textoNormalizado = texto.ToLower().Replace(" ", "");
        return textoNormalizado == InvertirTexto(textoNormalizado);
    }
}
  • Operaciones de conversión: Métodos para convertir entre diferentes formatos o tipos.
public class Conversor
{
    public static double CelsiusAFahrenheit(double celsius)
    {
        return (celsius * 9 / 5) + 32;
    }
    
    public static double FahrenheitACelsius(double fahrenheit)
    {
        return (fahrenheit - 32) * 5 / 9;
    }
}
  • Métodos de fábrica: Para crear instancias de objetos de manera controlada.
public class Producto
{
    public string Nombre { get; private set; }
    public decimal Precio { get; private set; }
    
    // Constructor privado
    private Producto(string nombre, decimal precio)
    {
        Nombre = nombre;
        Precio = precio;
    }
    
    // Método de fábrica estático
    public static Producto Crear(string nombre, decimal precio)
    {
        if (string.IsNullOrEmpty(nombre))
            throw new ArgumentException("El nombre no puede estar vacío");
            
        if (precio < 0)
            throw new ArgumentException("El precio no puede ser negativo");
            
        return new Producto(nombre, precio);
    }
}

En este ejemplo, el constructor de Producto es privado, y la única forma de crear instancias es a través del método estático Crear, que valida los parámetros antes de crear el objeto.

Métodos de extensión

Una aplicación especial de los métodos estáticos en C# son los métodos de extensión, que permiten "añadir" métodos a tipos existentes sin modificar su código fuente. Estos métodos deben estar en una clase estática y usar la palabra clave this en el primer parámetro:

public static class StringExtensions
{
    public static bool EsEmail(this string texto)
    {
        return texto.Contains("@") && texto.Contains(".");
    }
    
    public static string PrimeraLetraMayuscula(this string texto)
    {
        if (string.IsNullOrEmpty(texto))
            return texto;
            
        return char.ToUpper(texto[0]) + texto.Substring(1);
    }
}

Una vez definidos, estos métodos se pueden usar como si fueran métodos de instancia del tipo extendido:

string email = "usuario@ejemplo.com";
bool esValido = email.EsEmail(); // Usa el método de extensión

string nombre = "juan";
string nombreFormateado = nombre.PrimeraLetraMayuscula(); // Devuelve "Juan"

Ejemplo práctico: Validador de datos

Veamos un ejemplo más completo de una clase de utilidad con métodos estáticos para validar diferentes tipos de datos:

public static class Validador
{
    public static bool EsNumeroValido(string texto)
    {
        return int.TryParse(texto, out _);
    }
    
    public static bool EsEmailValido(string email)
    {
        if (string.IsNullOrEmpty(email))
            return false;
            
        // Validación simple de email
        return email.Contains("@") && email.Contains(".");
    }
    
    public static bool EsCodigoPostalValido(string cp)
    {
        if (string.IsNullOrEmpty(cp))
            return false;
            
        // Código postal español: 5 dígitos
        return cp.Length == 5 && EsNumeroValido(cp);
    }
    
    public static bool EsTelefonoValido(string telefono)
    {
        if (string.IsNullOrEmpty(telefono))
            return false;
            
        // Eliminar espacios y guiones
        string telefonoLimpio = telefono.Replace(" ", "").Replace("-", "");
        
        // Teléfono español: 9 dígitos
        return telefonoLimpio.Length == 9 && EsNumeroValido(telefonoLimpio);
    }
}

Y así podríamos utilizarlo:

// Validar diferentes datos
string numero = "123";
string email = "usuario@ejemplo.com";
string cp = "28001";
string telefono = "612-345-678";

Console.WriteLine($"¿Es número válido? {Validador.EsNumeroValido(numero)}");
Console.WriteLine($"¿Es email válido? {Validador.EsEmailValido(email)}");
Console.WriteLine($"¿Es CP válido? {Validador.EsCodigoPostalValido(cp)}");
Console.WriteLine($"¿Es teléfono válido? {Validador.EsTelefonoValido(telefono)}");

Métodos estáticos vs métodos de instancia

Es importante entender cuándo usar métodos estáticos y cuándo usar métodos de instancia:

  • Usa métodos estáticos cuando:

  • La operación no depende del estado de un objeto específico

  • La funcionalidad es independiente y autocontenida

  • Necesitas una utilidad global accesible desde cualquier parte

  • Usa métodos de instancia cuando:

  • La operación depende del estado del objeto

  • Cada instancia puede comportarse de manera diferente

  • Necesitas polimorfismo (sobrescribir métodos)

Ejemplo comparativo

Veamos un ejemplo que ilustra la diferencia entre métodos estáticos y de instancia:

public class Rectangulo
{
    // Propiedades de instancia
    public double Ancho { get; set; }
    public double Alto { get; set; }
    
    // Constructor
    public Rectangulo(double ancho, double alto)
    {
        Ancho = ancho;
        Alto = alto;
    }
    
    // Método de instancia: depende del estado del objeto
    public double CalcularArea()
    {
        return Ancho * Alto;
    }
    
    // Método estático: no depende de ninguna instancia
    public static double CalcularArea(double ancho, double alto)
    {
        return ancho * alto;
    }
}

Podemos usar estos métodos de la siguiente manera:

// Usando el método de instancia
Rectangulo rect = new Rectangulo(5, 3);
double area1 = rect.CalcularArea(); // Usa las propiedades del objeto

// Usando el método estático
double area2 = Rectangulo.CalcularArea(5, 3); // Requiere pasar todos los datos

En este ejemplo, el método de instancia CalcularArea() utiliza las propiedades del objeto, mientras que el método estático CalcularArea(double, double) requiere que se le pasen todos los datos necesarios como parámetros.

Consideraciones de rendimiento

Los métodos estáticos pueden ofrecer algunas ventajas de rendimiento en ciertos escenarios:

  • No requieren creación de instancias, lo que ahorra memoria.
  • Pueden ser optimizados por el compilador más fácilmente.
  • Son ligeramente más rápidos de invocar que los métodos de instancia.

Sin embargo, estas ventajas suelen ser mínimas y no deberían ser el factor principal para decidir entre métodos estáticos y de instancia. La decisión debe basarse principalmente en el diseño y la naturaleza de la funcionalidad.

Clases estáticas

Las clases estáticas en C# son un tipo especial de clase que está diseñada exclusivamente para contener miembros estáticos. A diferencia de las clases normales, las clases estáticas no pueden ser instanciadas, lo que significa que no podemos crear objetos a partir de ellas utilizando el operador new.

Una clase estática se declara utilizando la palabra clave static antes de la palabra class:

public static class Matematicas
{
    // Miembros estáticos
}

Características principales de las clases estáticas

Las clases estáticas tienen varias características distintivas:

  • No pueden ser instanciadas - No es posible crear objetos de una clase estática.
  • Solo pueden contener miembros estáticos - Todos los métodos, propiedades, campos y eventos deben ser estáticos.
  • No pueden contener constructores de instancia - Solo pueden tener un constructor estático.
  • No pueden heredar de otras clases ni ser heredadas por otras clases.
  • No pueden implementar interfaces.

Declaración y uso de una clase estática

Veamos un ejemplo básico de una clase estática que proporciona funcionalidad matemática:

public static class Matematicas
{
    // Campo estático
    public static readonly double PI = 3.14159265359;
    
    // Método estático
    public static double CalcularAreaCirculo(double radio)
    {
        return PI * radio * radio;
    }
    
    // Otro método estático
    public static double CalcularPerimetroCirculo(double radio)
    {
        return 2 * PI * radio;
    }
}

Para utilizar esta clase, simplemente accedemos a sus miembros a través del nombre de la clase:

// Acceder a un campo estático
Console.WriteLine($"El valor de PI es: {Matematicas.PI}");

// Llamar a métodos estáticos
double area = Matematicas.CalcularAreaCirculo(5);
double perimetro = Matematicas.CalcularPerimetroCirculo(5);

Console.WriteLine($"Área del círculo: {area}");
Console.WriteLine($"Perímetro del círculo: {perimetro}");

Constructor estático

Una clase estática puede tener un constructor estático que se ejecuta una sola vez cuando la clase se carga en memoria. Este constructor se utiliza para inicializar los campos estáticos o realizar otras tareas de configuración:

public static class Configuracion
{
    public static string RutaArchivos { get; private set; }
    public static int TiempoEspera { get; private set; }
    
    // Constructor estático
    static Configuracion()
    {
        Console.WriteLine("Inicializando la configuración...");
        RutaArchivos = @"C:\Datos\";
        TiempoEspera = 30;
    }
}

El constructor estático se ejecutará automáticamente la primera vez que se acceda a cualquier miembro de la clase:

// Esto provocará la ejecución del constructor estático
string ruta = Configuracion.RutaArchivos;
Console.WriteLine($"Ruta de archivos: {ruta}");

Casos de uso comunes para clases estáticas

Las clases estáticas son ideales para varios escenarios:

  • Clases de utilidad: Colecciones de métodos relacionados que realizan operaciones comunes.
public static class StringUtil
{
    public static string InvertirTexto(string texto)
    {
        char[] caracteres = texto.ToCharArray();
        Array.Reverse(caracteres);
        return new string(caracteres);
    }
    
    public static string QuitarEspacios(string texto)
    {
        return texto.Replace(" ", "");
    }
    
    public static int ContarPalabras(string texto)
    {
        if (string.IsNullOrWhiteSpace(texto))
            return 0;
            
        return texto.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Length;
    }
}
  • Clases de constantes: Para agrupar valores constantes relacionados.
public static class ConfiguracionApp
{
    public const string NOMBRE_APP = "Mi Aplicación";
    public const string VERSION = "1.0.0";
    public const int MAX_CONEXIONES = 100;
    public const int TIMEOUT_SEGUNDOS = 30;
}
  • Clases de extensión: Para definir métodos de extensión.
public static class IntExtensions
{
    public static bool EsPar(this int numero)
    {
        return numero % 2 == 0;
    }
    
    public static bool EsPrimo(this int numero)
    {
        if (numero <= 1) return false;
        if (numero <= 3) return true;
        
        if (numero % 2 == 0 || numero % 3 == 0) return false;
        
        for (int i = 5; i * i <= numero; i += 6)
        {
            if (numero % i == 0 || numero % (i + 2) == 0)
                return false;
        }
        
        return true;
    }
}

Estos métodos de extensión se pueden usar como si fueran métodos de instancia del tipo int:

int numero = 7;
bool esPar = numero.EsPar();      // Devuelve false
bool esPrimo = numero.EsPrimo();  // Devuelve true

Console.WriteLine($"¿{numero} es par? {esPar}");
Console.WriteLine($"¿{numero} es primo? {esPrimo}");

Ejemplo práctico: Clase de validación

Veamos un ejemplo más completo de una clase estática para validar diferentes tipos de datos:

public static class Validador
{
    // Validar si una cadena es un número entero
    public static bool EsEntero(string texto)
    {
        return int.TryParse(texto, out _);
    }
    
    // Validar si una cadena es un número decimal
    public static bool EsDecimal(string texto)
    {
        return decimal.TryParse(texto, out _);
    }
    
    // Validar si una cadena tiene el formato de DNI español (8 dígitos y una letra)
    public static bool EsDNI(string texto)
    {
        if (string.IsNullOrEmpty(texto) || texto.Length != 9)
            return false;
            
        string numeros = texto.Substring(0, 8);
        char letra = char.ToUpper(texto[8]);
        
        if (!EsEntero(numeros))
            return false;
            
        // Letras válidas para DNI español
        string letrasValidas = "TRWAGMYFPDXBNJZSQVHLCKE";
        int indice = int.Parse(numeros) % 23;
        
        return letra == letrasValidas[indice];
    }
    
    // Validar si una fecha está en un rango válido
    public static bool EsFechaValida(DateTime fecha, DateTime minimo, DateTime maximo)
    {
        return fecha >= minimo && fecha <= maximo;
    }
}

Y así podríamos utilizarlo:

// Validar diferentes datos
string numero = "123";
string decimal = "45.67";
string dni = "12345678Z";
DateTime fechaNacimiento = new DateTime(1990, 5, 15);

Console.WriteLine($"¿Es entero? {Validador.EsEntero(numero)}");
Console.WriteLine($"¿Es decimal? {Validador.EsDecimal(decimal)}");
Console.WriteLine($"¿Es DNI válido? {Validador.EsDNI(dni)}");

// Validar si la fecha está entre 1950 y hoy
bool fechaValida = Validador.EsFechaValida(
    fechaNacimiento,
    new DateTime(1950, 1, 1),
    DateTime.Today
);
Console.WriteLine($"¿Fecha válida? {fechaValida}");

Ejemplo: Clase de utilidad para archivos

Otro ejemplo útil es una clase estática para operaciones comunes con archivos:

public static class ArchivoUtil
{
    // Obtener la extensión de un archivo
    public static string ObtenerExtension(string rutaArchivo)
    {
        return Path.GetExtension(rutaArchivo).ToLower();
    }
    
    // Verificar si un archivo es una imagen
    public static bool EsImagen(string rutaArchivo)
    {
        string[] extensionesImagen = { ".jpg", ".jpeg", ".png", ".gif", ".bmp" };
        string extension = ObtenerExtension(rutaArchivo);
        
        return extensionesImagen.Contains(extension);
    }
    
    // Crear un nombre de archivo único basado en la fecha y hora
    public static string GenerarNombreUnico(string prefijo, string extension)
    {
        string timestamp = DateTime.Now.ToString("yyyyMMddHHmmss");
        return $"{prefijo}_{timestamp}{extension}";
    }
    
    // Convertir tamaño en bytes a formato legible
    public static string FormatearTamaño(long bytes)
    {
        string[] sufijos = { "B", "KB", "MB", "GB", "TB" };
        int i = 0;
        double tamaño = bytes;
        
        while (tamaño >= 1024 && i < sufijos.Length - 1)
        {
            tamaño /= 1024;
            i++;
        }
        
        return $"{tamaño:0.##} {sufijos[i]}";
    }
}

Uso de esta clase de utilidad:

// Verificar si un archivo es una imagen
string archivo = "foto.jpg";
bool esImagen = ArchivoUtil.EsImagen(archivo);
Console.WriteLine($"¿Es imagen? {esImagen}");

// Generar un nombre único para un archivo
string nombreUnico = ArchivoUtil.GenerarNombreUnico("documento", ".pdf");
Console.WriteLine($"Nombre único: {nombreUnico}");

// Formatear un tamaño de archivo
long tamaño = 1536000;
string tamañoFormateado = ArchivoUtil.FormatearTamaño(tamaño);
Console.WriteLine($"Tamaño: {tamañoFormateado}");  // Muestra "1.5 MB"

Ventajas de las clases estáticas

  • Organización del código: Agrupan funcionalidad relacionada en un solo lugar.
  • Facilidad de uso: No requieren crear instancias para utilizar su funcionalidad.
  • Rendimiento: Pueden ser más eficientes al no requerir instanciación.
  • Claridad: Indican claramente que la clase proporciona funcionalidad de utilidad.

Limitaciones de las clases estáticas

  • No soportan polimorfismo: No pueden heredar ni ser heredadas.
  • Estado global: Los datos estáticos son compartidos por toda la aplicación, lo que puede causar problemas en entornos multihilo.
  • Acoplamiento: El código que usa clases estáticas está más acoplado, lo que puede dificultar las pruebas unitarias.
  • Flexibilidad reducida: No pueden implementar interfaces ni usar patrones de diseño basados en instancias.

Cuándo usar clases estáticas

Las clases estáticas son más adecuadas cuando:

  • La funcionalidad no requiere mantener un estado entre llamadas.
  • Los métodos realizan operaciones independientes y autocontenidas.
  • Necesitas agrupar utilidades relacionadas que no cambian su comportamiento.
  • Quieres proporcionar funcionalidad global sin necesidad de instanciación.

Por ejemplo, las clases Math, File y Directory del espacio de nombres System en .NET son ejemplos de clases estáticas bien diseñadas que proporcionan funcionalidad de utilidad.

// Ejemplos de uso de clases estáticas de .NET
double raiz = Math.Sqrt(16);                  // Clase Math
bool existe = File.Exists("archivo.txt");     // Clase File
string[] archivos = Directory.GetFiles("C:/"); // Clase Directory

En resumen, las clases estáticas son una herramienta poderosa en C# para organizar funcionalidad de utilidad y operaciones que no requieren estado de instancia, proporcionando una forma clara y eficiente de agrupar métodos relacionados.

CONSTRUYE TU CARRERA EN IA Y PROGRAMACIÓN SOFTWARE

Accede a +1000 lecciones y cursos con certificado. Mejora tu portfolio con certificados de superación para tu CV.

30 % DE DESCUENTO

Plan mensual

19.00 /mes

13.30 € /mes

Precio normal mensual: 19 €
63 % DE DESCUENTO

Plan anual

10.00 /mes

7.00 € /mes

Ahorras 144 € al año
Precio normal anual: 120 €
Aprende CSharp online

Ejercicios de esta lección Miembros estáticos

Evalúa tus conocimientos de esta lección Miembros estáticos con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Todas las lecciones de CSharp

Accede a todas las lecciones de CSharp y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Introducción A C#

Introducción Y Entorno

Creación De Proyecto C#

Introducción Y Entorno

Variables Y Constantes

Sintaxis

Tipos De Datos

Sintaxis

Operadores

Sintaxis

Control De Flujo

Sintaxis

Funciones

Sintaxis

Estructuras De Control Iterativo

Sintaxis

Interpolación De Strings

Sintaxis

Estructuras De Control Condicional

Sintaxis

Manejo De Valores Nulos

Sintaxis

Clases Y Encapsulación

Programación Orientada A Objetos

Objetos

Programación Orientada A Objetos

Constructores Y Destructores

Programación Orientada A Objetos

Herencia

Programación Orientada A Objetos

Polimorfismo

Programación Orientada A Objetos

Genéricos

Programación Orientada A Objetos

Métodos Virtuales Y Sobrecarga

Programación Orientada A Objetos

Clases Abstractas

Programación Orientada A Objetos

Interfaces

Programación Orientada A Objetos

Propiedades Y Encapsulación

Programación Orientada A Objetos

Métodos De Extensión

Programación Orientada A Objetos

Clases Y Objetos

Programación Orientada A Objetos

Clases Parciales

Programación Orientada A Objetos

Miembros Estáticos

Programación Orientada A Objetos

Tuplas Y Tipos Anónimos

Programación Orientada A Objetos

Arrays Y Listas

Colecciones Y Linq

Diccionarios

Colecciones Y Linq

Conjuntos, Colas Y Pilas

Colecciones Y Linq

Uso De Consultas Linq

Colecciones Y Linq

Linq Avanzado

Colecciones Y Linq

Colas Y Pilas

Colecciones Y Linq

Conjuntos

Colecciones Y Linq

Linq Básico

Colecciones Y Linq

Delegados Funcionales

Programación Funcional

Records

Programación Funcional

Expresiones Lambda

Programación Funcional

Linq Funcional

Programación Funcional

Fundamentos De La Programación Funcional

Programación Funcional

Pattern Matching

Programación Funcional

Testing Unitario Con Xunit

Testing

Excepciones

Excepciones

Delegados

Programación Asíncrona

Eventos

Programación Asíncrona

Lambdas

Programación Asíncrona

Uso De Async Y Await

Programación Asíncrona

Tareas

Programación Asíncrona

Accede GRATIS a CSharp y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  • Comprender qué son los miembros estáticos y cómo se diferencian de los miembros de instancia.
  • Aprender a declarar y utilizar campos y propiedades estáticas en C#.
  • Entender la declaración y uso de métodos estáticos, incluyendo métodos de extensión.
  • Conocer las características, ventajas y limitaciones de las clases estáticas.
  • Aplicar miembros estáticos en casos prácticos como utilidades, validaciones y contadores globales.