Suprimindo os avisos "nunca é usado" e "nunca é atribuído a" em C #

107

Eu tenho um arquivo HTTPSystemDefinitions.cs no projeto C # que basicamente descreve o ISAPI do Windows mais antigo para consumo por código gerenciado.

Isso inclui o conjunto completo de Estruturas relevantes para a ISAPI, não todas ou que são consumidas por código. Na compilação, todos os membros do campo dessas estruturas estão causando um aviso como o seguinte: -

O campo de aviso 'UnionSquare.ISAPI.HTTP_FILTER_PREPROC_HEADERS.SetHeader' nunca é atribuído e sempre terá seu valor padrão nulo

ou

Aviso O campo 'UnionSquare.ISAPI.HTTP_FILTER_PREPROC_HEADERS.HttpStatus' nunca é usado

Eles podem ser desativados com #pragma warning disable? Em caso afirmativo, quais seriam os números de erro correspondentes? Se não, posso fazer mais alguma coisa? Tenha em mente que eu apenas o que fazer para este arquivo, é importante que eu receba avisos como este vindo de outros arquivos.

Editar

Estrutura de exemplo: -

struct HTTP_FILTER_PREPROC_HEADERS
{
    //
    //  For SF_NOTIFY_PREPROC_HEADERS, retrieves the specified header value.
    //  Header names should include the trailing ':'.  The special values
    //  'method', 'url' and 'version' can be used to retrieve the individual
    //  portions of the request line
    //

    internal GetHeaderDelegate GetHeader;
    internal SetHeaderDelegate SetHeader;
    internal AddHeaderDelegate AddHeader;

    UInt32  HttpStatus;               // New in 4.0, status for SEND_RESPONSE
    UInt32  dwReserved;               // New in 4.0
}
AnthonyWJones
fonte
Você pode mostrar a declaração desses campos, ou melhor, a estrutura em que eles estão? ou seja, Dê um exemplo.
Lasse V. Karlsen
11
Se forem definições de interoperabilidade, então normalmente você [StructLayout(LayoutKind.Sequential)]deve garantir que o layout da memória está correto (na implementação atual será mesmo sem este atributo, mas AFAIK não é garantido). Se bem me lembro, o compilador C # detecta a presença desse atributo e suprime automaticamente os avisos, pois sabe que os campos devem estar lá para interoperabilidade. (Posso estar errado sobre isso, postando como um comentário em vez de uma resposta).
Greg Beech,
@Greg: Essa é uma informação útil que investigarei. Prefiro que o aviso não seja gerado em vez de suprimi-lo.
AnthonyWJones,
1
1 para usar StructLayout. Parece mais limpo do que suprimir os próprios avisos.
Deanna
@GregBeech Você está certo! Isso ainda se aplica a projetos .NET Standard no VS2017.
zwcloud

Respostas:

195

Sim, eles podem ser suprimidos.

Normalmente, me oponho a suprimir avisos, mas, neste caso, structs usados ​​para interoperabilidade requerem absolutamente que alguns campos estejam presentes, mesmo que você nunca pretenda (ou possa) usá-los, então, neste caso, acho que deve ser justificado .

Normalmente, para suprimir esses dois avisos, você consertaria o código ofensivo. O primeiro ("... nunca é usado") é geralmente um cheiro de código de sobras de versões anteriores do código. Talvez o código tenha sido excluído, mas os campos deixados para trás.

O segundo é geralmente um cheiro de código para campos usados ​​incorretamente. Por exemplo, você pode escrever incorretamente o novo valor de uma propriedade de volta na própria propriedade, nunca gravando no campo de apoio.


Para suprimir avisos de "O campo XYZ nunca é usado ", faça o seguinte:

#pragma warning disable 0169
... field declaration
#pragma warning restore 0169

Para suprimir avisos para "O campo XYZ nunca é atribuído a e sempre terá seu valor padrão XX ", faça o seguinte:

#pragma warning disable 0649
... field declaration
#pragma warning restore 0649

Para encontrar você mesmo esses números de aviso (ou seja, como eu sabia usar 0169 e 0649), faça o seguinte:

  • Compile o código normalmente, isso adicionará alguns avisos à sua lista de erros no Visual Studio
  • Mude para a janela Output e Build output e procure os mesmos avisos
  • Copie o código de aviso de 4 dígitos da mensagem relevante, que deve ser assim:

    C: \ Dev \ VS.NET \ ConsoleApplication19 \ ConsoleApplication19 \ Program.cs (10,28): aviso CS 0649 : O campo 'ConsoleApplication19.Program.dwReserved' nunca é atribuído e sempre terá seu valor padrão 0


Advertência : de acordo com o comentário de @Jon Hanna , talvez alguns avisos sejam necessários para isso, para futuros descobridores desta pergunta e resposta.

  • Em primeiro lugar, o ato de suprimir um aviso é semelhante a engolir comprimidos para dor de cabeça. Claro, às vezes pode ser a coisa certa a fazer, mas não é uma solução abrangente. Às vezes, uma dor de cabeça é um sintoma real que você não deve mascarar, o mesmo com os avisos. É sempre melhor tentar tratar os avisos corrigindo sua causa, em vez de apenas removê-los cegamente da saída do build.
  • Dito isso, se você precisar suprimir um aviso, siga o padrão que descrevi acima. A primeira linha de código #pragma warning disable XYZK,, desativa o aviso para o resto do arquivo ou pelo menos até que um correspondente #pragma warning restore XYZKseja encontrado. Minimize o número de linhas em que você desativa esses avisos. O padrão acima desativa o aviso para apenas uma linha.
  • Além disso, como Jon menciona, um comentário explicando por que você está fazendo isso é uma boa ideia. Desativar um aviso é definitivamente um cheiro de código quando feito sem causa, e um comentário impedirá que futuros mantenedores percam tempo se perguntando por que você fez isso, ou mesmo removendo-o e tentando consertar os avisos.
Lasse V. Karlsen
fonte
9
Eu recomendaria, além da resposta acima, que o escopo da desativação seja o menor possível (para evitar desativá-la em algum lugar onde seja útil) e sempre acompanhar uma desativação com um comentário explicando por que você está desativando, por exemplo, //exists for interopem este caso.
Jon Hanna
Muito obrigado. É uma escolha estranha que o VS não inclua uma coluna para esses números na janela Lista de Erros.
AnthonyWJones
2
Como diz Jon, comentar o "porquê" é muito importante. Além disso, geralmente adiciono pelo menos parte do texto da mensagem de aviso ao comentário, por exemplo, // Suprimir o aviso "nunca é atribuído a ...". Poupe aos futuros mantenedores o aborrecimento de ter que consultar o código de aviso - afinal, pode ser você!
Tom Bushell
1
Não é imediatamente óbvio, mas você pode usar Localizar na janela Saída via CTRL + F, digitar "aviso", clicar em "Localizar tudo" e obter todos os avisos rapidamente, com os números dos avisos exibidos. Dito isso, o [StructLayout(LayoutKind.Sequential)]atributo lida com a interoperabilidade muito melhor de acordo com o comentário de Greg Beech sobre a questão.
Ryan Buddicom
2
Comentando para dizer que para usuários Unity3D, os números de aviso são 0414 para campos privados e 0219 para variáveis ​​locais, não 169 (o que emite um aviso sobre não foi possível restaurar o aviso).
Draco18s não confia mais em SE
14

Outra "solução" para corrigir esses avisos é criar a estrutura public. Os avisos não são emitidos porque o compilador não pode saber se os campos estão ou não sendo usados ​​(atribuídos) fora do assembly.

Dito isso, os componentes de "interoperabilidade" geralmente não devem ser públicos, mas sim internalou private.

floele
fonte
2
Legal, isso esconde o aviso ... mas definir structcomo publicé mais provável que seja um erro do que o aviso que estamos tentando mascarar. (Você provavelmente não deve expor desnecessariamente os tipos usados ​​para implementação interna e os tipos com campos públicos provavelmente não pertencem a uma API pública). Apenas para reforçar o seu conselho de que tais tipos devem ser “ao invés internalou private” ;-).
binki
muito obrigado - isso é o que eu precisava. Estou usando JsonConvert.DeserializeObjecte desserializando em uma classe pública que tem apenas todas as propriedades expostas para que eu saiba o que será retornado. Apenas torná-la uma classe pública vazia com todas as strings públicas é um bom código curto e agora não há mais avisos. Talvez usar uma classe dinâmica seja melhor, pois você não precisa declarar explicitamente o que está no array, mas acho que esta será uma boa referência para qualquer pessoa que pretenda usar o objeto.
user1274820
6

Eu pedi ao VS para gerar o esqueleto de implementação para System.ComponentModel.INotifyPropertyChangede os eventos foram implementados como campos que acionaram os avisos CS0067.

Como alternativa à solução dada na resposta aceita , converti os campos em propriedades e o aviso desapareceu .

Isso faz sentido, uma vez que a sintaxe de declaração de propriedade sugar é compilada em um campo mais os métodos getter e / ou setter (adicionar / remover no meu caso) que fazem referência ao campo. Isso satisfaz o compilador e os avisos não são gerados:

struct HTTP_FILTER_PREPROC_HEADERS
{
    //
    //  For SF_NOTIFY_PREPROC_HEADERS, retrieves the specified header value.
    //  Header names should include the trailing ':'.  The special values
    //  'method', 'url' and 'version' can be used to retrieve the individual
    //  portions of the request line
    //

    internal GetHeaderDelegate GetHeader {get;set;}
    internal SetHeaderDelegate SetHeader { get; set; }
    internal AddHeaderDelegate AddHeader { get; set; }

    UInt32 HttpStatus { get; set; }               // New in 4.0, status for SEND_RESPONSE
    UInt32 dwReserved { get; set; }               // New in 4.0
}
Pencho Ilchev
fonte
Sua solução é muito mais elegante do que desativar o aviso, mas pode interferir com alguns atributos apenas de campo, por exemplo, MarshalAsAttribute.
HuBeZa
1
Informação: Os campos privados reais gerados nesta situação podem ter nomes "estranhos" como <GetHeader>k__BackingField, dependendo dos detalhes de implementação do compilador C # usado.
Jeppe Stig Nielsen
1

Os usuários de C / C ++ devem (void)var;suprimir avisos de variáveis ​​não utilizadas. Acabei de descobrir que você também pode suprimir avisos de variáveis ​​não utilizadas em C # com operadores bit a bit:

        uint test1 = 12345;
        test1 |= 0; // test1 is still 12345

        bool test2 = true;
        test2 &= false; // test2 is now false

Ambas as expressões não produzem avisos de variáveis ​​não utilizadas nos compiladores VS2010 C # 4.0 e Mono 2.10.

Ceztko
fonte
4
Funciona para uint, mas não para outros tipos, como Exception. Você conhece um truque genérico equivalente ao C / C ++ var;?
manuell
1
@manuell olá do futuro! Você pode usar error.ToString();para uma variável do tipoException
Sv443
Obrigado a partir de agora. Esse truque adiciona código real em tempo de execução, certo?
manuell