Referencias anulables en C# 8.0 y posteriores (II): el operador !

“Time keeps flowing like a river…”
The Alan Parsons Project, “Time” (1981)

Ante todo, mis mayores deseos de que este 2021 sea mucho mejor para todos los lectores que el recién terminado 2020.

El tiempo sigue fluyendo (como un río hacia el mar, dijo Alan Parsons), y hace tanto que no escribía una entrada aquí que ya .NET 5.0 y C# 9.0 están disponibles oficialmente. Pero antes de empezar a hablar sobre las  características que se añadieron a la nueva versión del lenguaje, nos quedan todavía algunas cosas dignas de mencionar con relación a las referencias anulables (nullable references), de las que empezamos a hablar en mi post anterior.

Con relación al consumo de librerías que aprovechen esta potente característica, hay que destacar que Microsoft ha hecho un buen trabajo a la hora de anotar las librerías de .NET de manera que cualquier programador que utilice un ensamblado pueda aprovechar las indicaciones que éste nos ofrezca en relación con la anulabilidad de sus argumentos y el valor de retorno. Si bien existían ciertas dudas de que se pudiera entregar un conjunto completo de anotaciones para el lanzamiento oficial de .NET 5.0 y C# 9.0 debido a las limitaciones causadas por el COVID, el reto se cumplió en lo fundamental; en la página de Github Changes to Nullable Reference Type Annotations in .NET 6.0 se habla de un 94% de cobertura actual (.NET 5.0). En ese mismo enlace se detallan las API que falta por anotar y aquellas en las que se han cometido imprecisiones que serán corregidas en .NET 6.0.

En lo relativo a la creación o adaptación de código para hacer uso de esta característica, la vez anterior enumeramos un par de hechos fundamentales:

  • Mientras tanto no se activen las referencias anulables en un proyecto y/o fichero fuente específico, los datos de tipos por referencia en C# 8.0 y posteriores continuarán siendo para el compilador anulables (esto es, capaces de aceptar el valor null) por compatibilidad hacia atrás; pero tan pronto se active la característica, el compilador asumirá que todas las variables, etc. de tipos por referencia son por defecto no anulables, tal como ocurre con los tipos por valor, a menos que se indique explícitamente lo contrario.
  • La acción de «indicar lo contrario» se lleva a cabo añadiendo un signo de interrogación (?) detrás del nombre del tipo en la especificación de la variable, tal cual se hace para los tipos por valor:
           string? middleName;  // puede ser nulo

La otra pequeña adición al lenguaje relacionada con las referencias anulables es el llamado null-forgiving operator (literalmente «operador para perdonar los nulos»), que se describe oficialmente aquí. Se representa mediante un signo de admiración (!) detrás de cualquier expresión de tipo por referencia, y no tiene ningún efecto en tiempo de ejecución: simplemente informa al compilador de que una expresión no es nula, aún cuando el analizador de flujo (que no es omnisapiente) no pueda demostrarlo, y que no debe producir las advertencias asociadas a la posible anulabilidad de la expresión. Es similar a una conversión de tipo explícita (cast) para conversiones anulable/no anulable, con la particularidad de que no se genera comprobación alguna en el código IL. Un ejemplo muy simple podría ser el siguiente:

    01  class Program
    02  {
    03      static void Main()
    04      {
    05          var initValue = GetInitialValue(useNull:false);
    06          System.Console.WriteLine(initValue!.Length);
    07      }
    08
    09      static string? GetInitialValue(bool useNull)
    10      {
    11          return useNull ? null : string.Empty;
    12      }
    13  }

Sin el operador ! de la línea 06, el compilador produciría el mensaje:

    CS8602: Dereference of a possibly null reference [line 06]

Nosotros, que sabemos que GetInitialValue no devolverá null si le pasamos false, podemos aprovechar aquí el nuevo operador para evitar la advertencia.

En general, este operador se debe utilizar con cierta precaución; no obstante, en una próxima entrada presentaremos dos escenarios habituales en los que su uso es conveniente, e incluso imprescindible. ¡Hasta entonces!

奥克塔维奥


Referencia musical: El músico inglés Alan Parsons ya se había asegurado un puesto de primera línea en la historia del pop-rock desde principios de los años ´70, cuando fungió como ingeniero de sonido de varios discos de referencia obligatoria, como «Let It Be» (The Beatles, 1970) o «The Dark Side of the Moon» (Pink Floyd, 1973), entre otros. No contento con eso, creó su propia banda, The Alan Parsons Project, con la que nos ha deleitado desde la segunda mitad de los ´70 hasta nuestros días. Personalmente, mi disco favorito de Alan Parsons es el primero, «Tales of Mystery and Imagination» (1976), con canciones basadas en poemas y cuentos de Edgar Allan Poe como «The Raven» («El cuervo»), «The Tell-Tale Heart» («El corazón delator») o «The Fall of the House of Usher» («La caída de la casa Usher»).

Octavio Hernandez

Desarrollador y consultor en tecnologías .NET. Microsoft C# MVP entre 2004 y 2010.

Deja un comentario

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