Ciclos de aviso do C#

Novos avisos e erros podem ser apresentados em cada versão do compilador do C#. Quando novos avisos puderem ser relatados sobre o código existente, esses avisos serão apresentados em um sistema de aceitação chamado de ciclo de aviso. O sistema de aceitação determina que você deve tomar medidas para habilitar novos avisos ao observá-los no código existente. Os ciclos de aviso são habilitados usando o elemento AnalysisLevel no arquivo de projeto. Quando <TreatWarningsAsErrors>true</TreatWarningsAsErrors> é especificado, o ciclo de aviso habilitado gera erros. Os diagnósticos do ciclo de aviso 5 foram adicionados no C# 9. Os diagnósticos do ciclo de aviso 6 foram adicionados no C# 10. Os diagnósticos do ciclo de aviso 7 foram adicionados no C# 11. Os diagnósticos do ciclo de avisos 8 foram adicionados ao C# 12.

CS9123 – Tomar endereço de local ou parâmetro no método assíncrono pode criar um buraco de coleta de lixo.

Ciclo de aviso 8

O operador & não deve ser usado em parâmetros ou variáveis locais em métodos assíncronos. O seguinte código produz o CS9123:

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

CS8981 – O nome do tipo contém apenas caracteres ASCII com letras minúsculas.

Ciclo de aviso 7

As novas palavras-chave adicionadas para C# serão todos caracteres ASCII em letras minúsculas. Esse aviso garante que nenhum dos tipos entre em conflito com as futuras palavras-chave. O código a seguir produz o CS8981:

public class lowercasename
{
}

Você pode resolver esse aviso, renomeando o tipo para incluir pelo menos um caractere ASCII que não seja em letras minúsculas, como um caractere em letras maiúsculas, um dígito ou um sublinhado.

CS8826 – As declarações de método parcial têm diferenças de assinatura.

Ciclo de aviso 6

Este aviso corrige algumas inconsistências no relatório de diferenças entre assinaturas de método parcial. O compilador sempre relatou um erro quando as assinaturas de método parcial criaram assinaturas CLR diferentes. Agora, o compilador relata o CS8826 quando as assinaturas são sintaticamente diferentes do C#. Considere a classe parcial a seguir:

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);
}

A implementação de classe parcial a seguir gera vários exemplos 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) { }
}

Observação

Se a implementação de um método usar um tipo de referência não anulável, quando a outra declaração aceitar tipos de referência anulável, o CS8611 será gerado, ao invés do CS8826.

Para corrigir os casos desses avisos, verifique se as duas assinaturas correspondem.

CS7023 – Um tipo estático é usado em uma expressão 'is' ou 'as'.

Ciclo de aviso 5

As expressões is e as sempre retornam false para um tipo estático, pois não é possível criar instâncias de um tipo estático. O código a seguir produz o 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");
    }
}

O compilador relata esse aviso porque o teste de tipo nunca pode ter êxito. Para corrigir esse aviso, remova o teste e remova os códigos executados somente se o teste tiver êxito. No exemplo anterior, a cláusula else sempre é executada. O corpo do método pode ser substituído por esta única linha:

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

CS8073 – O resultado da expressão é sempre 'false' (ou 'true').

Ciclo de aviso 5

Os operadores == e != sempre retornam false (ou true), ao comparar uma instância de um tipo struct com o null. O código a seguir demonstra esse aviso. Suponha que S seja um struct que definiu operator == e 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 corrigir esse erro, remova a verificação nula e o código que seriam executados se o objeto fosse null.

CS8848 – O operador 'from' não pode ser usado aqui devido à precedência. Use parênteses para evitar ambiguidade.

Ciclo de aviso 5

Os exemplos a seguir demonstram esse aviso. A expressão é associada incorretamente devido à precedência dos 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 corrigir esse erro, coloque a expressão de consulta entre parênteses:

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)];

Os membros devem ser totalmente atribuídos, usando a variável não atribuída (CS8880, CS8881, CS8882, CS8883, CS8884, CS8885, CS8886, CS8887)

Ciclo de aviso 5

Vários avisos melhoram a análise de atribuição definitiva para os tipos struct declarados em assemblies importados. Todos esses novos avisos são gerados quando um struct em um assembly importado inclui um campo inacessível (geralmente um private campo) de um tipo de referência, conforme mostrado no exemplo a seguir:

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

Os exemplos a seguir mostram os avisos gerados com base na análise de atribuição definitiva aprimorada:

  • CS8880: a propriedade autoimplementada 'Property' precisa ser totalmente atribuída, antes que o controle seja retornado ao chamador.
  • CS8881: o campo 'field' deve ser totalmente atribuído, antes que o controle seja retornado ao chamador.
  • CS8882: o parâmetro externo 'parameter' deve ser atribuído, antes que o controle saia do método atual.
  • CS8883: uso da propriedade autoimplementada possivelmente não atribuída 'Property'.
  • CS8884: uso do campo possivelmente não atribuído 'Field'
  • CS8885: o objeto 'this' não pode ser usado, antes que todos os campos sejam atribuídos.
  • CS8886: uso do parâmetro de saída não atribuído 'parameterName'.
  • CS8887: uso da variável local não atribuída '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;
    }
}

Você pode corrigir qualquer um desses avisos, inicializando ou atribuindo o struct importado ao valor padrão:

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 – O método não será usado como ponto de entrada, pois o ponto de entrada síncrono 'method' foi encontrado.

Ciclo de aviso 5

Esse aviso é gerado em todos os candidatos de ponto de entrada assíncrono, quando você tem vários pontos de entrada válidos, incluindo um ou mais pontos de entrada síncronos.

O seguinte exemplo gera o erro CS8892:

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

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

Observação

O compilador sempre usa o ponto de entrada síncrono. Caso haja vários pontos de entrada síncronos, você receberá um erro do compilador.

Para corrigir esse aviso, remova ou renomeie o ponto de entrada assíncrono.

CS8897 – Os tipos estáticos não podem ser usados como parâmetros

Ciclo de aviso 5

Os membros de uma interface não podem declarar parâmetros cujo tipo é uma classe estática. O código a seguir demonstra CS8897 e CS8898:

public static class Utilities
{
    // elided
}

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

    // CS8898
    public Utilities GetUtility();
}

Para corrigir esse aviso, altere o tipo de parâmetro ou remova o método.

CS8898 – Os tipos estáticos não podem ser usados como tipos de retorno

Ciclo de aviso 5

Os membros de uma interface não podem declarar um tipo de retorno que seja uma classe estática. O código a seguir demonstra CS8897 e CS8898:

public static class Utilities
{
    // elided
}

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

    // CS8898
    public Utilities GetUtility();
}

Para corrigir esse aviso, altere o tipo de retorno ou remova o método.