Подавление предупреждений «никогда не используется» и «никогда не назначается» в C #

107

У меня есть файл HTTPSystemDefinitions.cs в проекте C #, который в основном описывает старые ISAPI Windows для использования управляемым кодом.

Сюда входит полный набор структур, относящихся к ISAPI, не все или которые используются кодом. При компиляции все элементы полей этих структур вызывают предупреждение, подобное следующему: -

Поле предупреждения 'UnionSquare.ISAPI.HTTP_FILTER_PREPROC_HEADERS.SetHeader' никогда не назначается и всегда будет иметь значение по умолчанию null

или

Предупреждение Поле UnionSquare.ISAPI.HTTP_FILTER_PREPROC_HEADERS.HttpStatus никогда не используется

Можно ли их отключить #pragma warning disable? Если да, то каковы будут соответствующие номера ошибок? Если нет, я могу что-то еще сделать? Имейте в виду, что я должен делать это только для этого файла, важно, чтобы я видел подобные предупреждения, исходящие от других файлов.

редактировать

Пример структуры: -

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
}
ЭнтониУ Джонс
источник
Можете ли вы показать объявление этих полей или, скорее, структуру, в которой они находятся? т.е. приведите пример.
Лассе В. Карлсен,
11
Если это определения взаимодействия, то обычно вы должны [StructLayout(LayoutKind.Sequential)]убедиться, что макет памяти правильный (в текущей реализации он будет даже без этого атрибута, но AFAIK это не гарантируется). Если я правильно помню, компилятор C # обнаруживает наличие этого атрибута и автоматически подавляет эти предупреждения, поскольку знает, что поля должны быть там для взаимодействия. (Я мог ошибаться в этом, поэтому отправляю как комментарий вместо ответа).
Грег Бич
@Greg: Это полезная информация, которую я исследую. Я бы предпочел, чтобы предупреждение не генерировалось, а не подавляло их.
AnthonyWJones 01
1
+1 за использование StructLayout. Это кажется чище, чем подавление самих предупреждений.
Deanna
@GregBeech Вы правы! Это по-прежнему относится к проектам .NET Standard на VS2017.
zwcloud

Ответы:

195

Да, их можно подавить.

Обычно я против подавления предупреждений, но в этом случае структуры, используемые для взаимодействия, абсолютно требуют наличия некоторых полей, даже если вы никогда не собираетесь (или не можете) их использовать, поэтому в этом случае я думаю, что это должно быть оправдано .

Обычно, чтобы подавить эти два предупреждения, вы исправляете проблемный код. Первый («... никогда не используется») обычно представляет собой запах остатков кода от более ранних версий кода. Возможно, код был удален, но поля остались позади.

Второй - обычно запах кода для неправильно используемых полей. Например, вы можете неправильно записать новое значение свойства обратно в само свойство, никогда не записывая в резервное поле.


Чтобы подавить предупреждения для « Поле XYZ никогда не используется », выполните следующие действия:

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

Чтобы подавить предупреждения для « Поле XYZ никогда не назначается и всегда будет иметь значение по умолчанию XX », выполните следующие действия:

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

Чтобы самостоятельно найти такие номера предупреждений (например, как я узнал, что использовать 0169 и 0649), вы делаете следующее:

  • Скомпилируйте код как обычно, это добавит некоторые предупреждения в ваш список ошибок в Visual Studio.
  • Переключитесь на окно вывода и вывод сборки и ищите те же предупреждения
  • Скопируйте 4-значный код предупреждения из соответствующего сообщения, которое должно выглядеть следующим образом:

    C: \ Dev \ VS.NET \ ConsoleApplication19 \ ConsoleApplication19 \ Program.cs (10,28): предупреждение CS 0649 : поле 'ConsoleApplication19.Program.dwReserved' никогда не назначается и всегда будет иметь значение по умолчанию 0


Предостережение : согласно комментарию @Jon Hanna , возможно, для этого нужно сделать несколько предупреждений для будущих искателей этого вопроса и ответа.

  • Прежде всего, подавление предупреждения сродни глотанию таблеток от головной боли. Конечно, иногда это может быть правильным поступком, но это не универсальное решение. Иногда головная боль - это реальный симптом, который не следует маскировать, как и предупреждения. Всегда лучше попытаться устранить предупреждения, устраняя их причину, а не просто удалять их вслепую из результатов сборки.
  • Сказав это, если вам нужно подавить предупреждение, следуйте схеме, которую я изложил выше. Первая строка кода #pragma warning disable XYZKотключает предупреждение для остальной части этого файла или, по крайней мере, до тех пор, пока не #pragma warning restore XYZKбудет найдено соответствующее предупреждение . Сведите к минимуму количество строк, на которых вы отключите эти предупреждения. Приведенный выше шаблон отключает предупреждение только для одной строки.
  • Кроме того, как упоминает Джон, неплохо было бы пояснить, почему вы это делаете. Отключение предупреждения определенно является запахом кода, если оно сделано без причины, и комментарий не позволит будущим сопровождающим тратить время на то, чтобы гадать, зачем вы это сделали, или даже удаляя его и пытаясь исправить предупреждения.
Лассе В. Карлсен
источник
9
Я бы порекомендовал дополнительно к ответу выше, чтобы объем отключения был как можно меньше (чтобы не отключать его где-то там, где это полезно) и всегда сопровождать отключение комментарием о том, почему вы отключаете, например, //exists for interopв Это дело.
Джон Ханна,
Большое спасибо. Странно, что VS не включает столбец для этих чисел в окне списка ошибок.
AnthonyWJones,
2
Как говорит Джон, очень важно комментировать «почему». Кроме того, я обычно добавляю в комментарий хотя бы часть текста предупреждения, например, // Подавить предупреждение "никогда не назначено ...". Избавьте будущих сопровождающих от необходимости искать код предупреждения - в конце концов, это можете быть вы!
Том Бушелл,
1
Это не сразу очевидно, но вы можете использовать «Найти» в окне вывода с помощью CTRL + F, ввести «предупреждение», щелкнуть «Найти все» и быстро получать каждое предупреждение с отображением номеров предупреждений. Тем не менее, согласно [StructLayout(LayoutKind.Sequential)]комментарию Грега Бича по этому вопросу, атрибут обрабатывает взаимодействие намного лучше.
Ryan Buddicom
2
В комментариях говорится, что для пользователей Unity3D номера предупреждений: 0414 для частных полей и 0219 для локальных переменных, а не 169 (вместо этого выдается предупреждение о невозможности восстановить предупреждение).
Draco18s больше не доверяет SE
14

Еще одно «решение» для устранения этих предупреждений - создание struct public. В этом случае предупреждения не выдаются, потому что компилятор не может знать, используются ли поля (назначаются) вне сборки.

Тем не менее, «Interop» компоненты должны , как правило , не публично, а internalили private.

Floele
источник
2
Хорошо, это действительно скрывает предупреждение ... но установка такой structкак publicболее вероятно будет ошибкой, чем предупреждение, которое мы пытаемся замаскировать. (Вероятно, вам не следует без надобности раскрывать типы, используемые для внутренней реализации, и типы с общедоступными полями, вероятно, не принадлежат общедоступному API). Просто чтобы подкрепить ваш совет, что такие типы должны быть «скорее internalили private» ;-).
binki
обалденное спасибо - это то, что мне нужно. Я использую JsonConvert.DeserializeObjectи десериализируюсь в общедоступный класс, в котором представлены все свойства, так что я знаю, что будет возвращено. Просто сделать его открытым классом, пустым со всеми общедоступными строками, - это хороший короткий код, и теперь никаких предупреждений. Возможно, было бы лучше использовать динамический класс, поскольку вам не нужно явно указывать, что находится в массиве, но я думаю, что это будет хорошая ссылка для всех, кто надеется использовать объект.
user1274820 04
6

Я заставил VS сгенерировать каркас реализации, System.ComponentModel.INotifyPropertyChangedи события были реализованы как поля, которые вызвали предупреждения CS0067.

В качестве альтернативы решению, приведенному в принятом ответе, я преобразовал поля в свойства, и предупреждение исчезло .

Это имеет смысл, поскольку сахар синтаксиса объявлений свойств компилируется в поле плюс методы получения и / или установки (в моем случае добавить / удалить), которые ссылаются на поле. Это удовлетворяет компилятор, и предупреждения не появляются:

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
}
Пенчо Ильчев
источник
Ваше решение более изящно, чем отключение предупреждения, но оно может мешать работе некоторых атрибутов только для полей, например MarshalAsAttribute.
HuBeZa 05
1
Информация: Фактические частные поля, сгенерированные в этой ситуации, могут иметь «странные» имена, например <GetHeader>k__BackingField, в зависимости от деталей реализации используемого компилятора C #.
Йеппе Стиг Нильсен,
1

Пользователи C / C ++ должны (void)var;подавлять предупреждения о неиспользуемых переменных. Я только что обнаружил, что вы также можете подавить предупреждения о неиспользуемых переменных в C # с помощью побитовых операторов:

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

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

Оба выражения не вызывают предупреждений о неиспользуемых переменных в компиляторах VS2010 C # 4.0 и Mono 2.10.

Ceztko
источник
4
Работает uint, но не для других типов, например Exception. Вы знаете общий трюк, эквивалентный C / C ++ var;?
Мануэль
1
@manuell привет из будущего! Вы можете использовать error.ToString();для переменной типаException
Sv443,
Теперь спасибо. Этот трюк действительно добавляет реальный код во время выполнения, верно?
мануэль