La forma correcta de validar nulos (valores null) en C#
Sabías de is null y de is not null? Es momento que los utilices y seas un programador completo!

Qué me estás diciendo? podrías estar diciendo tú. Luego dirías: Gerson, pero si la validación de nulos es sencilla:

            var alumno = repository.GetById(19);
            if(alumno != null)
            {
                Console.WriteLine($"El nombre del alumno es {alumno.Name}");
            }

Pues déjame decirte que esa forma de validar, aunque masivamente utilizada, no es la mejor opción. Técnicamente es insegura y por lo tanto hasta cierto punto, incorrecta.

Y por qué estarás preguntándote, hey Gerson déjate de rodeos dime el porqué.

Para entender esto hay que repasar un poquito de teoría, veamos...

Sobrecarga

En el paradigma orientado a objetos la sobrecarga implica creación de dos o más métodos con el mismo nombre pero con diferentes signaturas, es decir distintos parámetros y/o funcionalidad.

Esto hace que podamos definir más de un comportamiento para un método y el que se aplique uno u otro va a depender de los parámetros que le enviemos.

En este artículo explico a profundidad este concepto 👌

Operadores

Son sentencias básicas del lenguaje de programación, en este caso C#, y son compatibles con la gran mayoría de tipos de datos y por ello permiten realizar operaciones básicas con dichos tipos.

Con tipos me refiero a tipos de datos y que se dividen en tipos por valor y tipos por referencia, por ejemplo en C# tenemos: int, char, string, decimal, bool, etcétera. Más información aquí.

Estos operadores pueden ser:

  • Lógicos
  • Aritméticos
  • De comparación
  • bit a bit y de desplazamiento
  • De igualdad

Aquí tienes la documentación oficial de los operadores en C#

Sobrecarga de operadores

Conociendo entonces qué es un operador y además qué es sobrecarga, debo mencionarte que es posible sobrecargar muchos de los operadores existentes.

Ese es el caso de los operadores == y !=

Y ese es el primer motivo por el cual confiar a ciegas en estos operadores puede ser peligroso ya que dichos operadores pueden tener comportamientos alterados y quizá no podamos saberlo.

En esta página de documentación oficial de Microsoft puedes ver cuáles operadores aceptan sobrecarga y cuáles no, y si te fijas, el operador is no es 'sobrecargable'.

Comparte lo aprendido con tu equipo. Foto de Annie Spratt en Unsplash

Forma correcta de validar nulos

La forma de validar si un objeto es null o no es con un operador no sobrecargable, me refiero a is.

Y desde la versión 9 de C# puedes utilizar is seguido de not null, con lo que puedes validar exactamente lo mismo que con == y != sólo que de una forma más adecuada y profesional.

Los motivos para esto son dos, por si no ha quedado claro hasta ahora:

  • Mayor seguridad al tener la certeza que la comprobación es fidedigna y precisa
  • Mejor legibilidad y lectura del código, ya que resulta más natural al lenguaje humano

Caso práctico

Hagamos un pequeño pero esclarecedor ejemplo mediante una aplicación de consola.

Tengo mi clase Student con dos propiedades y en donde voy a sobrecargar los operadores == y != introduciendo a propósito un bug en ellos

    internal class Student
    {
        public int id { get; set; }
        public string Name { get; set; }

        public static bool operator ==(Student b1, Student b2)
        {
            if ((object)b2 == null)
                return true; //Aquí introduje un bug ya que sin importar los objetos si el segundo objeto es nulo retorna true

            return b1.Equals(b2);
        }
        public static bool operator !=(Student b1, Student b2)
        {
            if ((object)b2 == null)
                return true; //aquí introduje un bug similar al anterior

            return b1.Equals(b2);
        }
    }

Tengo una clase llamada StudentRepository cuya función va a ser la de proveer un método de recuperación de datos, es decir un método que nos devuelva información, imitando el comportamiento de una clase que trae data desde la base de datos.

    internal class StudentRepository
    {
        private List<Student> students = new List<Student>()
        {
            new Student() { id = 1, Name = "Gerson"},
            new Student() { id = 2, Name = "Yasmín"},
            new Student() { id = 3, Name = "Estefany"},
            new Student() { id = 4, Name = "Pery"},
            new Student() { id = 5, Name = "Guille"},
            new Student() { id = 6, Name = "Angel"},
            new Student() { id = 7, Name = "Rosa"}
        };

        public Student GetById(int id)
        {
            return students.Find(x => x.id == id);
        }
    }

Nota cómo tenemos sólo 7 registros con sus respectivos id correlativos.

Finalmente tenemos la clase Program desde donde ejecutaremos el programa de consola y una validación para nuestra prueba

    public class Program
    {
        public static void Main(string[] args)
        {
            GetData();
        }
                
        public static void GetData()
        {
            StudentRepository repository = new StudentRepository();
            var alumno = repository.GetById(19); //intentamos obtener un alumno que no existe

            //Validación 'clásica'
            if (alumno != null)
                Console.WriteLine($"El nombre del alumno es {alumno.Name}");
            else
                Console.WriteLine("Alumno NO existe");
            
            //Validación adecuada
            if (alumno is not null)
                Console.WriteLine($"El nombre del alumno es {alumno.Name}");
            else
                Console.WriteLine("Alumno NO existe");
        }
    }

Ejecutamos el programa para comprobar resultados, esperamos que la consola nos arroje el mensaje que el alumno no existe, ya que no hay un alumno con id 19 y además tengo mi validación para asegurarme de ello. Sin embargo obtengo esta excepción:

A pesar de tener mi validación en la línea 19 el programa ingresa a la línea 20 como si el objeto no fuese null, y en ese momento lanza una excepción al querer devolver un dato que no existe.

Sin duda, este no es el comportamiento esperado, y por qué pasó esto? Sencillo, es porque sobrecargamos el operador != el cual tenía un bug, esto echará a perder todas las validaciones con el operador != en todo el proyecto, lo cual es muy peligroso.

Te sorprenderías las veces que esto pasa en la vida real, los proyectos reales en las empresas al ser inmensos resulta difícil de detectar una sobrecarga o una modificación que altera comportamiento en el código en un lugar totalmente diferente.

Ahora probemos con la validación correcta mediante el operador is not null

Nota como la ejecución jamás entró en la línea 27, y al ser nulo el objeto entonces me muestra el mensaje adecuado y ya que is no acepta sobrecarga, puedo confiar en que validará siempre los nulos como es debido.

Todo este código está en este repo de mi Github 😉

Si esta entrada te ha encantado dev, compártela, no lo dudes! 🐿️

Créditos de foto principal: Foto de Nathan Dumlao en Unsplash

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *