Resolución de advertencias sobre los valores NULL

En este artículo se tratan las siguientes advertencias del compilador:

  • CS8597 - El valor generado puede ser NULL.
  • CS8600 - Se va a convertir un literal nulo o un posible valor nulo en un tipo que no acepta valores NULL.
  • CS8601 - Posible asignación de referencia nula.
  • CS8602 - Desreferencia de una referencia posiblemente NULL.
  • CS8603 - Posible tipo de valor devuelto de referencia nulo.
  • CS8604 - Posible argumento de referencia nulo para el parámetro.
  • CS8605 - Conversión unboxing a un valor posiblemente NULL.
  • CS8607 - Un posible valor NULL no se puede usar para un tipo marcado con [NotNull] o [DisallowNull].
  • CS8608 - La nulabilidad de los tipos de referencia del tipo no coincide con el miembro reemplazado.
  • CS8609 - La nulabilidad de los tipos de referencia en el tipo de valor devuelto no coincide con el miembro reemplazado.
  • CS8610 - La nulabilidad de los tipos de referencia del tipo de parámetro no coincide con el miembro reemplazado.
  • CS8611 - La nulabilidad de los tipos de referencia del tipo de parámetro no coincide con la declaración de método parcial.
  • CS8612 - La nulabilidad de los tipos de referencia del tipo no coincide con el miembro implementado de forma implícita.
  • CS8613 - La nulabilidad de los tipos de referencia en el tipo de valor devuelto no coincide con el miembro implementado de forma implícita.
  • CS8614 - La nulabilidad de los tipos de referencia del tipo de parámetro no coincide con el miembro implementado de forma implícita.
  • CS8615 - La nulabilidad de los tipos de referencia del tipo no coincide con el miembro implementado.
  • CS8616 - La nulabilidad de los tipos de referencia en el tipo de valor devuelto no coincide con el miembro implementado.
  • CS8617 - La nulabilidad de los tipos de referencia del tipo de parámetro no coincide con el miembro implementado.
  • CS8618 - Una variable que no acepta valores NULL debe contener un valor distinto de NULL al salir del constructor. Considere la posibilidad de declararla como que admite un valor NULL.
  • CS8619 - La nulabilidad de los tipos de referencia del valor no coincide con el tipo de destino.
  • CS8620 - El argumento no se puede usar para el parámetro debido a las diferencias en la nulabilidad de los tipos de referencia.
  • CS8621 - La nulabilidad de los tipos de referencia del tipo de valor devuelto no coincide con el delegado de destino (posiblemente debido a los atributos de nulabilidad).
  • CS8622 - La nulabilidad de los tipos de referencia del tipo de parámetro no coincide con el delegado de destino (posiblemente debido a los atributos de nulabilidad).
  • CS8624 - El argumento no se puede usar como salida debido a las diferencias en la nulabilidad de los tipos de referencia.
  • CS8625 - No se puede convertir un literal NULL en un tipo de referencia que no acepta valores NULL.
  • CS8629 - Un tipo que acepta valores NULL puede ser nulo.
  • CS8631 - El tipo no se puede usar como parámetro de tipo en el tipo o método genérico. La nulabilidad del argumento de tipo no coincide con el tipo de restricción.
  • CS8633 - La nulabilidad de las restricciones del parámetro de tipo del método no coincide con las restricciones del parámetro de tipo del método de interfaz. Considere usar una implementación de interfaz explícita en su lugar.
  • CS8634 - El tipo no se puede usar como parámetro de tipo en el tipo o método genérico. La nulabilidad del argumento de tipo no coincide con la restricción "class".
  • CS8643 - La nulabilidad de los tipos de referencia del especificador de interfaz explícito no coincide con la interfaz que el tipo implementa.
  • CS8644 - El tipo no implementa un miembro de interfaz. La nulabilidad de los tipos de referencia de la interfaz que implementa el tipo base no coincide.
  • CS8645 - El miembro ya está en la lista de interfaces del tipo con una nulabilidad diferente de los tipos de referencia.
  • CS8655 - La expresión switch no controla algunas entradas de tipo NULL (no es exhaustiva).
  • CS8667 - Las declaraciones de métodos parciales tienen una nulabilidad incoherente de las restricciones para el parámetro de tipo.
  • CS8670 - El inicializador de objeto o colección desreferencia el miembro posiblemente NULL de forma implícita.
  • CS8714 - El tipo no se puede usar como parámetro de tipo en el método o tipo genérico. La nulabilidad del argumento de tipo no coincide con la restricción "notnull".
  • CS8762 - El parámetro debe tener un valor que no sea nulo al salir.
  • CS8763 - Un método marcado como [DoesNotReturn] no debería devolver un valor.
  • CS8764 - La nulabilidad del tipo de valor devuelto no coincide con el miembro invalidado (posiblemente debido a los atributos de nulabilidad).
  • CS8765 - La nulabilidad del tipo de parámetro no coincide con el miembro invalidado (posiblemente debido a los atributos de nulabilidad).
  • CS8766 - La nulabilidad de los tipos de referencia del tipo de valor devuelto no coincide con el miembro implementado de forma implícita (posiblemente debido a los atributos de nulabilidad).
  • CS8767 - La nulabilidad de los tipos de referencia del tipo de parámetro no coincide con el miembro implementado de forma implícita (posiblemente debido a los atributos de nulabilidad).
  • CS8768 - La nulabilidad de los tipos de referencia del tipo de valor devuelto no coincide con el miembro implementado (posiblemente debido a los atributos de nulabilidad).
  • CS8769 - La nulabilidad de los tipos de referencia del tipo de parámetro no coincide con el miembro implementado (posiblemente debido a los atributos de nulabilidad).
  • CS8770 - El método carece de una anotación [DoesNotReturn] que coincida con un miembro implementado o invalidado.
  • CS8774 - El miembro debe tener un valor que no sea nulo al salir.
  • CS8776 - No se puede usar el miembro en este atributo.
  • CS8775 - El miembro debe tener un valor que no sea nulo al salir.
  • CS8777 - El parámetro debe tener un valor que no sea nulo al salir.
  • CS8819 - La nulabilidad de los tipos de referencia del tipo devuelto no coincide con la declaración de método parcial.
  • CS8824 - El parámetro debe tener un valor que no sea NULL al salir porque el parámetro no es NULL.
  • CS8825 - El valor devuelto no debe ser NULL porque el parámetro no es NULL.
  • CS8847 - La expresión switch no controla algunas entradas NULL (no es exhaustiva). Sin embargo, un patrón con una cláusula "when" puede coincidir correctamente con este valor.

El propósito de las advertencias sobre código que admite valores NULL es minimizar la posibilidad de que la aplicación produzca una excepción System.NullReferenceException cuando se ejecute. Para lograr este objetivo, el compilador usa análisis estáticos y emite advertencias cuando el código tiene construcciones que pueden provocar excepciones de referencias nulas. Para proporcionar al compilador información sobre su análisis estático, aplique anotaciones y atributos de tipo. Estas anotaciones y atributos describen la nulabilidad de argumentos, parámetros y miembros de los tipos. En este artículo, aprenderá diferentes técnicas para solucionar las advertencias sobre los valores NULL que el compilador genera a partir de su análisis estático. Las técnicas que se describen aquí son para código de C# en general. Aprenda a trabajar con tipos de referencia que aceptan valores NULL y con Entity Framework Core en Trabajar con tipos de referencia que aceptan valores NULL.

Solucionará casi todas las advertencias usando una de estas cuatro técnicas:

  • Agregar las comprobaciones necesarias sobre los valores NULL.
  • Agregar las anotaciones ? o !, que aceptan valores NULL.
  • Agregar atributos que describen la semántica NULL.
  • Inicializar las variables correctamente.

Posible desreferencia de los valores NULL

Este conjunto de advertencias le avisa de que está desreferenciando una variable cuyo null-state es maybe-null. Estas advertencias son:

  • CS8602 - Desreferencia de una referencia posiblemente NULL.
  • CS8670 - El inicializador de objeto o colección desreferencia el miembro posiblemente NULL de forma implícita.

En el siguiente código se muestra un ejemplo de cada una de las advertencias anteriores:

class Container
{
    public List<string>? States { get; set; }
}

internal void PossibleDereferenceNullExamples(string? message)
{
    Console.WriteLine(message.Length); // CS8602

    var c = new Container { States = { "Red", "Yellow", "Green" } }; // CS8670
}

En el ejemplo anterior, la advertencia se debe a que Container, c, puede tener un valor NULL para la propiedad States. La asignación de nuevos estados a una colección que podrían ser NULL provoca la advertencia.

Para quitar estas advertencias, debe agregar código para cambiar el null-state de esa variable a not-null (no es NULL) antes de desreferenciarla. La advertencia del inicializador de la colección puede ser más difícil de detectar. El compilador detecta que la colección puede ser NULL (maybe-null) cuando el inicializador agrega elementos a ella.

En muchos casos, puede corregir estas advertencias comprobando que una variable no es NULL antes de desreferenciarla. Tenga en cuenta lo siguiente que agrega una comprobación de valores null antes de eliminar la referencia al parámetro message:

void WriteMessageLength(string? message)
{
    if (message is not null)
    {
        Console.WriteLine(message.Length);
    }
    
}

En el ejemplo siguiente se inicializa el almacenamiento de respaldo para States y se quita el descriptor de acceso set. Los consumidores de la clase pueden modificar el contenido de la colección y el almacenamiento de la colección nunca es null:

class Container
{
    public List<string> States { get; } = new();
}

En algunos casos, estas advertencias pueden ser falsos positivos. Es posible que tenga un método de utilidad privada que haga pruebas sobre los valores NULL. El compilador no sabe que el método proporciona una comprobación de valores NULL. Fíjese en este ejemplo, que usa un método de utilidad privada, IsNotNull:

public void WriteMessage(string? message)
{
    if (IsNotNull(message))
        Console.WriteLine(message.Length);
}

El compilador advierte de que puede estar desreferenciando un valor NULL cuando se escribe la propiedad message.Length, porque su análisis estático determina que message puede ser null. Es posible que sepa que IsNotNull proporciona una comprobación de valores NULL y, cuando devuelve true, el null-state de message debe ser not-null. Debe indicar esos datos al compilador. Una forma de hacerlo es usando el operador que permite valores NULL, !. Puede cambiar la instrucción WriteLine para que coincida con el código siguiente:

Console.WriteLine(message!.Length);

El operador que permite valores NULL hace que la expresión sea not-null incluso si era maybe-null antes de aplicar !. En este ejemplo, una solución mejor es agregar un atributo a la firma de IsNotNull:

private static bool IsNotNull([NotNullWhen(true)] object? obj) => obj != null;

System.Diagnostics.CodeAnalysis.NotNullWhenAttribute informa al compilador de que el argumento utilizado para el parámetro obj es not-null cuando el método devuelve true. Cuando el método devuelve false, el argumento tiene el mismo null-state que tenía antes de la llamada al método.

Sugerencia

Hay un amplio conjunto de atributos que puede usar para describir cómo afectan los métodos y propiedades al null-state. Puede obtener información sobre ellos en el artículo de referencia del lenguaje sobre Atributos de análisis estático que aceptan valores NULL.

La corrección de una advertencia para desreferenciar una variable maybe-null implica una de estas tres técnicas:

  • Agregar una comprobación de valores NULL que falte.
  • Agregar atributos de análisis de valores NULL en las API para afectar al análisis estático de null-state del compilador. Estos atributos informan al compilador sobre si un valor devuelto o un argumento debe ser maybe-null o not-null después de llamar al método.
  • Aplicar el operador !, que permite valores NULL, a la expresión para forzar que el estado sea not-null.

Posible valor NULL asignado a una referencia que no acepta valores NULL

Este conjunto de advertencias le avisa de que va a asignar una variable cuyo tipo no acepta valores NULL a una expresión cuyo null-state es maybe-null. Estas advertencias son:

  • CS8597 - El valor generado puede ser NULL.
  • CS8600 - Se va a convertir un literal nulo o un posible valor nulo en un tipo que no acepta valores NULL.
  • CS8601 - Posible asignación de referencia nula.
  • CS8603 - Posible tipo de valor devuelto de referencia nulo.
  • CS8604 - Posible argumento de referencia nulo para el parámetro.
  • CS8605 - Conversión unboxing a un valor posiblemente NULL.
  • CS8625 - No se puede convertir un literal NULL en un tipo de referencia que no acepta valores NULL.
  • CS8629 - Un tipo que acepta valores NULL puede ser nulo.

El compilador emite estas advertencias al intentar asignar una expresión maybe-null a una variable que no acepta valores NULL. Por ejemplo:

string? TryGetMessage(int id) => "";

string msg = TryGetMessage(42);  // Possible null assignment.

Las distintas advertencias proporcionan detalles sobre el código, como la asignación, la asignación de conversión unboxing, las instrucciones "return", los argumentos de los métodos y las expresiones "throw".

Puede realizar una de estas tres acciones para solucionar estas advertencias. Una opción es agregar la anotación ? para convertir la variable en un tipo de referencia que acepta valores NULL. Ese cambio puede provocar otras advertencias. Cambiar una variable de una referencia que no acepta valores NULL a una que sí los acepta cambia su null-state predeterminado de not-null a maybe-null. El análisis estático del compilador puede encontrar instancias en las que se desreferencia una variable que es maybe-null.

El resto de acciones indican al compilador que el lado derecho de la asignación es not-null. Se podría comprobar si la expresión del lado derecho admite valores NULL antes de la asignación, como se muestra en el siguiente ejemplo:

string notNullMsg = TryGetMessage(42) ?? "Unknown message id: 42";

En los ejemplos anteriores se muestra la asignación al valor devuelto de un método. Puede anotar el método (o la propiedad) para indicar las situaciones en las que un método devuelve un valor not-null. System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute a menudo especifica que un valor devuelto es not-null cuando un argumento de entrada es not-null. Otra alternativa es agregar el operador que permite valores NULL, !, en el lado derecho:

string msg = TryGetMessage(42)!;

La corrección de una advertencia para asignar una expresión maybe-null a una variable not-null implica una de estas cuatro técnicas:

  • Cambiar el lado izquierdo de la asignación a un tipo que acepte valores NULL. Esta acción puede introducir nuevas advertencias al desreferenciar esa variable.
  • Proporcionar una comprobación de valores NULL antes de la asignación.
  • Anotar la API que genera el lado derecho de la asignación.
  • Agregar el operador que permite valores NULL al lado derecho de la asignación.

Referencia que no acepta valores NULL no inicializada

Este conjunto de advertencias le avisa de que va a asignar una variable cuyo tipo no acepta valores NULL a una expresión cuyo null-state es maybe-null. Estas advertencias son:

  • CS8618 - Una variable que no acepta valores NULL debe contener un valor distinto de NULL al salir del constructor. Considere la posibilidad de declararla como que admite un valor NULL.
  • CS8762 - El parámetro debe tener un valor que no sea nulo al salir.

Fíjese en la clase siguiente a modo de ejemplo:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

No se garantiza la inicialización de FirstName ni de LastName. Si este código es nuevo, considere la posibilidad de cambiar la interfaz pública. El ejemplo anterior podría actualizarse de la siguiente manera:

public class Person
{
    public Person(string first, string last)
    {
        FirstName = first;
        LastName = last;
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Si necesita crear un objeto Person antes de establecer el nombre, puede inicializar las propiedades mediante un valor no NULL predeterminado:

public class Person
{
    public string FirstName { get; set; } = string.Empty;
    public string LastName { get; set; } = string.Empty;
}

Otra alternativa puede ser cambiar esos miembros a tipos de referencia que aceptan valores NULL. La clase Person se puede definir de la siguiente manera si null debe permitirse para el nombre:

public class Person
{
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
}

El código existente puede necesitar otros cambios para informar al compilador sobre la semántica NULL de esos miembros. Es posible que haya creado varios constructores y que la clase tenga un método auxiliar privado que inicialice uno o varios miembros. Puede mover el código de inicialización a un único constructor y asegurarse de que todos los constructores llaman al que tiene el código de inicialización común. O puede usar los atributos System.Diagnostics.CodeAnalysis.MemberNotNullAttribute y System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute. Estos atributos informan al compilador de que un miembro es not-null después de que se llame al método. En el código siguiente se muestra un ejemplo de cada caso. La clase Person usa un constructor común al que llaman todos los demás constructores. La clase Student tiene un método auxiliar anotado con el atributo System.Diagnostics.CodeAnalysis.MemberNotNullAttribute:


using System.Diagnostics.CodeAnalysis;

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public Person() : this("John", "Doe") { }
}

public class Student : Person
{
    public string Major { get; set; }

    public Student(string firstName, string lastName, string major)
        : base(firstName, lastName)
    {
        SetMajor(major);
    }

    public Student(string firstName, string lastName) :
        base(firstName, lastName)
    {
        SetMajor();
    }

    public Student()
    {
        SetMajor();
    }

    [MemberNotNull(nameof(Major))]
    private void SetMajor(string? major = default)
    {
        Major = major ?? "Undeclared";
    }
}

Por último, puede usar el operador que permite valores NULL para indicar que un miembro se inicializa en otro código. Por dar otro ejemplo, fíjese en las siguientes clases que representan un modelo de Entity Framework Core:

public class TodoItem
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

public class TodoContext : DbContext
{
    public TodoContext(DbContextOptions<TodoContext> options)
        : base(options)
    {
    }

    public DbSet<TodoItem> TodoItems { get; set; } = null!;
}

La propiedad DbSet se inicializa en null!. Esto indica al compilador que la propiedad está establecida en un valor not-null. De hecho, la base DbContext realiza la inicialización del conjunto. El análisis estático del compilador no lo capta. Para más información sobre cómo trabajar con tipos de referencia que aceptan valores NULL y Entity Framework Core, consulte el artículo Cómo trabajar con tipos de referencia que aceptan valores NULL en EF Core.

La corrección de una advertencia de que no se ha inicializado un miembro que no acepta valores NULL implica una de estas cuatro técnicas:

  • Cambiar los constructores o inicializadores de campo para asegurarse de que se inicializan todos los miembros que no aceptan valores NULL.
  • Cambiar uno o varios miembros para que sean tipos que aceptan valores NULL.
  • Anotar los métodos auxiliares para indicar qué miembros están asignados.
  • Agregar un inicializador a null! para indicar que el miembro se inicializa en otro código.

Error de coincidencia en la declaración de nulabilidad

Muchas advertencias indican que las firmas no coinciden en su nulabilidad para los métodos, delegados o parámetros de tipo.

  • CS8608 - La nulabilidad de los tipos de referencia del tipo no coincide con el miembro reemplazado.
  • CS8609 - La nulabilidad de los tipos de referencia en el tipo de valor devuelto no coincide con el miembro reemplazado.
  • CS8610 - La nulabilidad de los tipos de referencia del tipo de parámetro no coincide con el miembro reemplazado.
  • CS8611 - La nulabilidad de los tipos de referencia del tipo de parámetro no coincide con la declaración de método parcial.
  • CS8612 - La nulabilidad de los tipos de referencia del tipo no coincide con el miembro implementado de forma implícita.
  • CS8613 - La nulabilidad de los tipos de referencia en el tipo de valor devuelto no coincide con el miembro implementado de forma implícita.
  • CS8614 - La nulabilidad de los tipos de referencia del tipo de parámetro no coincide con el miembro implementado de forma implícita.
  • CS8615 - La nulabilidad de los tipos de referencia del tipo no coincide con el miembro implementado.
  • CS8616 - La nulabilidad de los tipos de referencia en el tipo de valor devuelto no coincide con el miembro implementado.
  • CS8617 - La nulabilidad de los tipos de referencia del tipo de parámetro no coincide con el miembro implementado.
  • CS8619 - La nulabilidad de los tipos de referencia del valor no coincide con el tipo de destino.
  • CS8620 - El argumento no se puede usar para el parámetro debido a las diferencias en la nulabilidad de los tipos de referencia.
  • CS8621 - La nulabilidad de los tipos de referencia del tipo de valor devuelto no coincide con el delegado de destino (posiblemente debido a los atributos de nulabilidad).
  • CS8622 - La nulabilidad de los tipos de referencia del tipo de parámetro no coincide con el delegado de destino (posiblemente debido a los atributos de nulabilidad).
  • CS8624 - El argumento no se puede usar como salida debido a las diferencias en la nulabilidad de los tipos de referencia.
  • CS8631 - El tipo no se puede usar como parámetro de tipo en el tipo o método genérico. La nulabilidad del argumento de tipo no coincide con el tipo de restricción.
  • CS8633 - La nulabilidad de las restricciones del parámetro de tipo del método no coincide con las restricciones del parámetro de tipo del método de interfaz. Considere usar una implementación de interfaz explícita en su lugar.
  • CS8634 - El tipo no se puede usar como parámetro de tipo en el tipo o método genérico. La nulabilidad del argumento de tipo no coincide con la restricción "class".
  • CS8643 - La nulabilidad de los tipos de referencia del especificador de interfaz explícito no coincide con la interfaz que el tipo implementa.
  • CS8644 - El tipo no implementa un miembro de interfaz. La nulabilidad de los tipos de referencia de la interfaz que implementa el tipo base no coincide.
  • CS8645 - El miembro ya está en la lista de interfaces del tipo con una nulabilidad diferente de los tipos de referencia.
  • CS8667 - Las declaraciones de métodos parciales tienen una nulabilidad incoherente de las restricciones para el parámetro de tipo.
  • CS8714 - El tipo no se puede usar como parámetro de tipo en el método o tipo genérico. La nulabilidad del argumento de tipo no coincide con la restricción "notnull".
  • CS8764 - La nulabilidad del tipo de valor devuelto no coincide con el miembro invalidado (posiblemente debido a los atributos de nulabilidad).
  • CS8765 - La nulabilidad del tipo de parámetro no coincide con el miembro invalidado (posiblemente debido a los atributos de nulabilidad).
  • CS8766 - La nulabilidad de los tipos de referencia del tipo de valor devuelto no coincide con el miembro implementado de forma implícita (posiblemente debido a los atributos de nulabilidad).
  • CS8767 - La nulabilidad de los tipos de referencia del tipo de parámetro no coincide con el miembro implementado de forma implícita (posiblemente debido a los atributos de nulabilidad).
  • CS8768 - La nulabilidad de los tipos de referencia del tipo de valor devuelto no coincide con el miembro implementado (posiblemente debido a los atributos de nulabilidad).
  • CS8769 - La nulabilidad de los tipos de referencia del tipo de parámetro no coincide con el miembro implementado (posiblemente debido a los atributos de nulabilidad).
  • CS8819 - La nulabilidad de los tipos de referencia del tipo devuelto no coincide con la declaración de método parcial.

El código siguiente muestra la advertencia CS8764.

public class B
{
    public virtual string GetMessage(string id) => string.Empty;
}
public class D : B
{
    public override string? GetMessage(string? id) => default;
}

En el ejemplo anterior se muestra un método virtual en una clase base y un override con una nulabilidad diferente. La clase base devuelve una cadena que no acepta valores NULL, pero la clase derivada devuelve una cadena que sí los acepta. Si string y string? se invierten, se permitirá porque la clase derivada es más restrictiva. De forma similar, las declaraciones de parámetros deben coincidir. Los parámetros del método de invalidación pueden permitir valores NULL incluso cuando la clase base no los permite.

Otras situaciones pueden generar estas advertencias. Es posible que tenga un error de coincidencia entre una declaración del método de interfaz y la implementación de ese método. O bien, un tipo de delegado y la expresión de ese delegado pueden diferir. Un parámetro de tipo y el argumento de tipo pueden diferir en su nulabilidad.

Para corregir estas advertencias, actualice la declaración adecuada.

El código no coincide con la declaración de atributo

En las secciones anteriores se ha explicado cómo puede usar Atributos para el análisis estático que acepta valores NULL para informar al compilador sobre la semántica NULL del código. El compilador le advierte si el código no cumple las promesas de ese atributo:

  • CS8607 - Un posible valor NULL no se puede usar para un tipo marcado con [NotNull] o [DisallowNull].
  • CS8763 - Un método marcado como [DoesNotReturn] no debería devolver un valor.
  • CS8770 - El método carece de una anotación [DoesNotReturn] que coincida con un miembro implementado o invalidado.
  • CS8774 - El miembro debe tener un valor que no sea nulo al salir.
  • CS8775 - El miembro debe tener un valor que no sea nulo al salir.
  • CS8776 - No se puede usar el miembro en este atributo.
  • CS8777 - El parámetro debe tener un valor que no sea nulo al salir.
  • CS8824 - El parámetro debe tener un valor que no sea NULL al salir porque el parámetro no es NULL.
  • CS8825 - El valor devuelto no debe ser NULL porque el parámetro no es NULL.

Observe el método siguiente:

public bool TryGetMessage(int id, [NotNullWhen(true)] out string? message)
{
    message = null;
    return true;

}

El compilador genera una advertencia porque se asigna el parámetro messagenully el método devuelve true. El atributo NotNullWhen indica que eso no debe ocurrir.

Para solucionar estas advertencias, actualice el código para que coincida con las expectativas de los atributos que ha aplicado. Puede cambiar los atributos o el algoritmo.

Expresión switch exhaustiva

Las expresiones switch deben ser exhaustivas, es decir, deben controlar todos los valores de entrada. Incluso para los tipos de referencia que no aceptan valores NULL, debe tenerse en cuenta el valor null. El compilador emite advertencias cuando no se controla el valor NULL:

  • CS8655 - La expresión switch no controla algunas entradas de tipo NULL (no es exhaustiva).
  • CS8847 - La expresión switch no controla algunas entradas NULL (no es exhaustiva). Sin embargo, un patrón con una cláusula "when" puede coincidir correctamente con este valor.

El siguiente código de ejemplo muestra esta condición:

int AsScale(string status) =>
    status switch
    {
        "Red" => 0,
        "Yellow" => 5,
        "Green" => 10,
        { } => -1
    };

La expresión de entrada es string, no string?. El compilador sigue generando esta advertencia. El patrón { } controla todos los valores no NULL, pero no coincide con null. Para solucionar estos errores, puede agregar un caso null explícito o reemplazar { } por el patrón (de descarte) _. El patrón de descarte coincide con NULL y con cualquier otro valor.