Partilhar via


Ondas de aviso em C#

Novos avisos e erros podem ser introduzidos em cada versão do compilador C#. Quando novos avisos podem ser comunicados no código existente, esses avisos são introduzidos sob um sistema de aceitação referido como uma onda de aviso. O sistema de aceitação significa que você não deve ver novos avisos no código existente sem tomar medidas para habilitá-los. As ondas de aviso são ativadas usando o elemento AnalysisLevel no arquivo de projeto. Quando <TreatWarningsAsErrors>true</TreatWarningsAsErrors> especificado, os avisos de onda de aviso ativados geram erros. O diagnóstico da onda de aviso 5 foi adicionado no C# 9. O diagnóstico da onda de aviso 6 foi adicionado no C# 10. O diagnóstico da onda de aviso 7 foi adicionado no C# 11. Os diagnósticos da onda de aviso 8 foram adicionados no C# 12.

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

Onda de alerta 8

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

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

A partir do C# 13, esse código gera um erro de compilador.

CS8981 - O nome do tipo contém apenas caracteres ascii com caixa baixa.

Onda de alerta 7

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

public class lowercasename
{
}

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

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

Onda de alerta 6

Este aviso corrige algumas inconsistências no relatório de diferenças entre assinaturas parciais de método. O compilador sempre relatou um erro quando as assinaturas de método parcial criaram assinaturas CLR diferentes. Agora, o compilador relata CS8826 quando as assinaturas são sintaticamente diferentes C#. Considere a seguinte classe 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);
}

A seguinte implementação de classe parcial 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) { }
}

Nota

Se a implementação de um método usa um tipo de referência não anulável quando a outra declaração aceita tipos de referência anuláveis, CS8611 é gerado em vez de CS8826.

Para corrigir qualquer instância desses avisos, verifique se as duas assinaturas coincidem.

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

Onda de alerta 5

As is expressões e as sempre retornam false para um tipo estático porque você não pode criar instâncias de um tipo estático. O código a seguir produz 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 qualquer código executado somente se o teste foi bem-sucedido. No exemplo anterior, a else cláusula é sempre executada. Você pode substituir esse corpo de método por essa única linha:

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

CS8073 - O resultado da expressão é sempre 'falso' (ou 'verdadeiro').

Onda de alerta 5

Os == operadores e != sempre retornam false (ou true) ao comparar uma instância de um struct tipo com .null O código a seguir demonstra esse aviso. Suponha S que é um struct que define 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 for null.

CS8848 - O operador 'de' não pode ser usado aqui devido à precedência. Use parênteses para desambiguar.

Onda de alerta 5

Os exemplos a seguir demonstram esse aviso. A expressão liga-se 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 parênteses ao redor da expressão 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)];

Os membros devem estar plenamente atribuídos. Uso de variável não atribuída (CS8880, CS8881, CS8882, CS8883, CS8884, CS8885, CS8886, CS8887)

Onda de alerta 5

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

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

Os exemplos a seguir mostram os avisos gerados a partir da análise de atribuição definida aprimorada:

  • CS8880: A propriedade implementada automaticamente 'Propriedade' deve ser totalmente atribuída antes que o controle seja retornado ao chamador.
  • CS8881: O campo 'campo' deve ser totalmente atribuído antes que o controle seja retornado ao chamador.
  • CS8882: O parâmetro de saída 'parâmetro' deve ser atribuído antes que o controle deixe o método atual.
  • CS8883: Uso da propriedade auto-implementada possivelmente não atribuída 'Property'.
  • CS8884: Uso do campo possivelmente não atribuído 'Campo'
  • CS8885: O objeto 'this' não pode ser usado antes que todos os seus campos tenham sido 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 a struct importada ao seu 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 um ponto de entrada porque um ponto de entrada síncrono 'método' foi encontrado.

Onda de alerta 5

Esse aviso é gerado em todos os candidatos a 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 exemplo a seguir gera CS8892:

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

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

Nota

O compilador sempre usa o ponto de entrada síncrono. No caso de haver vários pontos de entrada síncronos, você recebe um erro do compilador.

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

CS8897 - Tipos estáticos não podem ser usados como parâmetros

Onda de alerta 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 - tipos estáticos não podem ser usados como tipos de retorno

Onda de alerta 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.