Olas de advertencias de C#

Se pueden introducir nuevas advertencias y errores en cada versión del compilador de C#. Cuando se puedan notificar nuevas advertencias en el código existente, esas advertencias se introducen en un sistema de participación denominado ola advertencias. El sistema de participación significa que no debería ver nuevas advertencias en el código existente sin tomar medidas para habilitarlas. Las olas de advertencias se habilitan mediante el elemento AnalysisLevel del archivo del proyecto. Cuando se especifica <TreatWarningsAsErrors>true</TreatWarningsAsErrors>, las advertencias de ola de advertencias habilitadas generan errores. Se han agregado diagnósticos de la ola de advertencias 5 en C# 9. Se han agregado diagnósticos de la ola de advertencias 6 en C# 10. Se han agregado diagnósticos de la ola de advertencias 7 en C# 11. Se agregaron diagnósticos de la ola de advertencias 8 en C# 12.

CS9123: tomar la dirección local o del parámetro en el método asincrónico puede crear un agujero de GC.

Ola de advertencias 8

El operador & no debe usarse en parámetros ni variables locales en métodos asincrónicos. El código siguiente produce el error CS9123:

public static async Task LogValue()
{
    int x = 1;
    unsafe {
        int* y = &x;
        Console.WriteLine(*y);
    }
    await Task.Delay(1000);
}

CS8981: El nombre de tipo solo contiene caracteres ASCII en minúsculas.

Ola de advertencias 7

Todas las palabras clave nuevas agregadas para C# serán caracteres ASCII en minúsculas. Esta advertencia garantiza que ninguno de los tipos entre en conflicto con palabras clave futuras. El código siguiente genera la advertencia CS8981:

public class lowercasename
{
}

Para solucionar esta advertencia, cambie el nombre del tipo para incluir al menos un carácter ASCII que no esté en minúscula, como un carácter en mayúsculas, un dígito o un carácter de subrayado.

CS8826: Las declaraciones de método parcial tienen diferencias de firma.

Ola de advertencias 6

Esta advertencia corrige algunas incoherencias en la comunicación de las diferencias entre firmas de método parcial. El compilador siempre notificaba un error cuando las firmas de método parcial creaban firmas CLR diferentes. Ahora, el compilador notifica CS8826 cuando las firmas son sintácticamente diferentes en C#. Fíjese en la siguiente clase parcial:

public partial class PartialType
{
    public partial void M1(int x);

    public partial T M2<T>(string s) where T : struct;

    public partial void M3(string s);


    public partial void M4(object o);
    public partial void M5(dynamic o);
    public partial void M6(string? s);
}

La siguiente implementación de clase parcial genera varios ejemplos de CS8626:

public partial class PartialType
{
    // Different parameter names:
    public partial void M1(int y) { }

    // Different type parameter names:
    public partial TResult M2<TResult>(string s) where TResult : struct => default;

    // Relaxed nullability
    public partial void M3(string? s) { }


    // Mixing object and dynamic
    public partial void M4(dynamic o) { }

    // Mixing object and dynamic
    public partial void M5(object o) { }

    // Note: This generates CS8611 (nullability mismatch) not CS8826
    public partial void M6(string s) { }
}

Nota

Si la implementación de un método usa un tipo de referencia que no acepta valores NULL cuando la otra declaración acepta tipos de referencia que aceptan valores NULL, se genera CS8611 en lugar de CS8826.

Para corregir cualquier instancia de estas advertencias, asegúrese de que las dos firmas coincidan.

CS7023: se usa un tipo estático en una expresión "is" o "as".

Ola de advertencias 5

Las expresiones is y as siempre devuelven false para un tipo estático porque no se pueden crear instancias de un tipo estático. El código siguiente genera la advertencia CS7023:

static class StaticClass
{
    public static void Thing() { }
}

void M(object o)
{
    // warning: cannot use a static type in 'is' or 'as'
    if (o is StaticClass)
    {
        Console.WriteLine("Can't happen");
    }
    else
    {
        Console.WriteLine("o is not an instance of a static class");
    }
}

El compilador notifica esta advertencia porque la prueba del tipo nunca tiene éxito. Para corregir esta advertencia, quite la prueba y quite cualquier código ejecutado solo si la prueba se realizó correctamente. En el ejemplo anterior, la cláusula else siempre se ejecuta. El cuerpo del método podría reemplazarse por esa sola línea:

Console.WriteLine("o is not an instance of a static class");

CS8073: El resultado de la expresión siempre es "false" (o "true").

Ola de advertencias 5

Los operadores == y != siempre devuelven false (o true) al comparar una instancia de un tipo struct con null. El código siguiente muestra esta advertencia. Supongamos que S es un elemento struct que ha definido operator == y operator !=:

class Program
{
    public static void M(S s)
    {
        if (s == null) { } // CS8073: The result of the expression is always 'false'
        if (s != null) { } // CS8073: The result of the expression is always 'true'
    }
}

struct S
{
    public static bool operator ==(S s1, S s2) => s1.Equals(s2);
    public static bool operator !=(S s1, S s2) => !s1.Equals(s2);
    public override bool Equals(object? other)
    {
        // Implementation elided
        return false;
    }
    public override int GetHashCode() => 0;

    // Other details elided...
}

Para corregir este error, quite la comprobación de valores NULL y el código que se ejecutaría si el objeto fuera null.

CS8848: El operador "from" no se puede usar aquí debido a la prioridad. Use paréntesis para eliminar la ambigüedad.

Ola de advertencias 5

A continuación, se muestran ejemplos de esta advertencia. La expresión se enlaza incorrectamente debido a la prioridad de los operadores.

bool b = true;
var source = new Src();
b = true;
source = new Src();
var a = b && from c in source select c;
Console.WriteLine(a);

var indexes = new Src2();
int[] array = { 1, 2, 3, 4, 5, 6, 7 };
var range = array[0..from c in indexes select c];

Para corregir este error, coloque paréntesis alrededor de la expresión de consulta:

bool b = true;
var source = new Src();
b = true;
source = new Src();
var a = b && (from c in source select c);
Console.WriteLine(a);

var indexes = new Src2();
int[] array = { 1, 2, 3, 4, 5, 6, 7 };
var range = array[0..(from c in indexes select c)];

Los miembros deben estar totalmente asignados, el uso de una variable sin asignar (CS8880, CS8881, CS8882, CS8883, CS8884, CS8885, CS8886, CS8887)

Ola de advertencias 5

Varias advertencias mejoran el análisis de asignación definido para los tipos struct declarados en ensamblados importados. Todas estas nuevas advertencias se generan cuando una estructura de un ensamblado importado incluye un campo inaccesible (normalmente un campo private) de un tipo de referencia, como se muestra en el ejemplo siguiente:

public struct Struct
{
    private string data = String.Empty;
    public Struct() { }
}

En los ejemplos siguientes se muestran las advertencias generadas a partir del análisis de asignación definido mejorado:

  • CS8880: Una propiedad implementada automáticamente "Property" debe estar totalmente asignada antes de devolver el control al autor de la llamada.
  • CS8881: El campo "field" debe asignarse completamente antes de devolver el control al autor de la llamada.
  • CS8882: Es necesario asignar el parámetro de salida "parameter" antes de que el control abandone el método actual.
  • CS8883: Uso de la propiedad "Property" implementada automáticamente posiblemente sin asignar.
  • CS8884: Uso del campo "Field" posiblemente sin asignar.
  • CS8885: El objeto "this" no se puede usar antes de que se hayan asignado todos sus campos.
  • CS8886: Uso del parámetro de salida sin asignar "parameterName".
  • CS8887: Uso de la variable local sin asignar "variableName".
public struct DefiniteAssignmentWarnings
{
    // CS8880
    public Struct Property { get; }
    // CS8881
    private Struct field;

    // CS8882
    public void Method(out Struct s)
    {

    }

    public DefiniteAssignmentWarnings(int dummy)
    {
        // CS8883
        Struct v2 = Property;
        // CS8884
        Struct v3 = field;
        // CS8885:
        DefiniteAssignmentWarnings p2 = this;
    }

    public static void Method2(out Struct s1)
    {
        // CS8886
        var s2 = s1;
        s1 = default;
    }

    public static void UseLocalStruct()
    {
        Struct r1;
        var r2 = r1;
    }
}

Puede corregir cualquiera de estas advertencias inicializando o asignando la estructura importada a su valor predeterminado:

public struct DefiniteAssignmentNoWarnings
{
    // CS8880
    public Struct Property { get; } = default;
    // CS8881
    private Struct field = default;

    // CS8882
    public void Method(out Struct s)
    {
        s = default;
    }

    public DefiniteAssignmentNoWarnings(int dummy)
    {
        // CS8883
        Struct v2 = Property;
        // CS8884
        Struct v3 = field;
        // CS8885:
        DefiniteAssignmentNoWarnings p2 = this;
    }

    public static void Method2(out Struct s1)
    {
        // CS8886
        s1 = default;
        var s2 = s1;
    }

    public static void UseLocalStruct()
    {
        Struct r1 = default;
        var r2 = r1;
    }
}

CS8892: El método no se usará como punto de entrada porque se ha encontrado un punto de entrada "method" sincrónico.

Ola de advertencias 5

Esta advertencia se genera en todos los candidatos de punto de entrada asincrónico cuando tiene varios puntos de entrada válidos, que incluyen uno o varios sincrónicos.

El ejemplo siguiente genera la advertencia CS8892:

public static void Main()
{
    RunProgram();
}

// CS8892
public static async Task Main(string[] args)
{
    await RunProgramAsync();
}

Nota:

El compilador siempre usa el punto de entrada sincrónico. En caso de que haya varios puntos de entrada sincrónicos, recibirá un error del compilador.

Para corregir esta advertencia, quite o cambie el nombre del punto de entrada asincrónico.

CS8897: No se pueden usar tipos estáticos como parámetros

Ola de advertencias 5

Los miembros de una interfaz no pueden declarar parámetros cuyo tipo sea una clase estática. El código siguiente muestra las advertencias CS8897 y CS8898:

public static class Utilities
{
    // elided
}

public interface IUtility
{
    // CS8897
    public void SetUtility(Utilities u);

    // CS8898
    public Utilities GetUtility();
}

Para corregir esta advertencia, cambie el tipo de parámetro o quite el método.

CS8898: Los tipos estáticos no se pueden usar como tipos de valor devuelto

Ola de advertencias 5

Los miembros de una interfaz no pueden declarar un tipo de valor devuelto que sea una clase estática. El código siguiente muestra las advertencias CS8897 y CS8898:

public static class Utilities
{
    // elided
}

public interface IUtility
{
    // CS8897
    public void SetUtility(Utilities u);

    // CS8898
    public Utilities GetUtility();
}

Para corregir esta advertencia, cambie el tipo de valor devuelto o quite el método .