Можно ли пометить функцию С# как "эта функция не перечисляет параметр IEnumerable"?
Множественное перечисление одного и того же перечисляемого является проблемой, которая была для нас проблемой производительности, поэтому мы пытаемся помешать этим предупреждениям в коде. Но есть общая функция расширения, которую мы имеем для того, чтобы выбрасывать исключения из нулевого параметра, которые генерируют много этих предупреждений. Его подпись выглядит следующим образом:
public static void VerifyArgumentIsNotNull<T>(this T value, string valueName) where T : class
Все, что он делает, это проверить значение null и бросить красиво отформатированный и локализованный (в зависимости от того, какой язык в данный момент играет в игру).
Когда эта функция используется в параметре IEnumerable, это делает анализ кода предупреждением о возможной множественной итерации IEnumerable, потому что анализатор не знает, что делает эта функция.
Я хотел бы поместить некоторый тег в эту функцию, который говорит: "Да, это берет перечислимый как вход, но не выполняет его итерацию и поэтому не следует считать возможной итерацией вызывающими". Есть ли такой тег? Я искал Интернет безрезультатно.
Ответы
Ответ 1
Да, то, что вы просите, очень возможно, но требует небольшой работы. ReSharper использует Аннотации кода, чтобы добавить подсказки к его движку анализа и понять смысл кода, с которым он должен работать. Недавно я записал вебинар с JetBrains под названием ReSharper Secrets, где я подробно расскажу о том, какие аннотации и как их использовать. Вы должны посмотреть его!
Здесь атрибут аннотации [NoEnumeration]
, который выполняет именно то, что вы просите, указывает, что данный аргумент IEnumerable
не указан, однако он не включен в значение по умолчанию Атрибуты аннотации кода, однако он определен в сборке JetBrains.Annotations.dll
.
Итак, после этого введения, вот что вам нужно сделать:
- (если вы еще этого не сделали), перейдите в "Параметры ReSharper", затем "Проверка кода" → "Аннотации кода" и нажмите кнопку Скопировать стандартную реализацию в буфер обмена.
- Создайте файл в любом из ваших (общих) проектов под названием
Annotations.cs
(или любое другое имя)
- Вставьте код из буфера обмена, полностью заменив все, что было ранее в
Annotations.cs
- Добавьте следующее определение в конец файла:
код:
/// <summary>
/// Indicates that IEnumarable, passed as parameter, is not enumerated.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class NoEnumerationAttribute : Attribute
{
}
После этого все, что осталось сделать, это поместить атрибут [NoEnumeration]
в аргумент value
, например:
public static void VerifyArgumentIsNotNull<T>([NoEnumeration] this T value, string valueName) where T : class
{
....
}
И это! Предупреждение исчезнет!
Bonus:
Есть 3 дополнительных атрибута, которые можно использовать для украшения этого метода, чтобы сделать его еще более полезным: [NotNull]
, [ContractAnnotation]
и [InvokerParameterName]
. Недавно я описал, что они делают (и короткую демонстрацию) в этой проблеме для аналогичного API под названием LiteGuard.
Аннотации - это весело:)
Ответ 2
Так как VerifyArgumentIsNotNull является общим, но не делает ничего конкретного, он может взять объект:
public static void VerifyArgumentIsNotNull(this object @object, string argumentName) { ... }
Resharper (9.11.) предполагает, что вызываемый метод не возвращает @object обратно в IEnumerable и, следовательно, нет предупреждений.
Обратите внимание, что отсутствие ограничения класса означает, что компилятор не может предупредить, если вы случайно передаете тип значения VerifyArgumentIsNotNull, но Resharper предупредит, что тип значения никогда не может быть нулевым.
Этот подход имеет дополнительное преимущество в сохранении JIT от создания экземпляра (закрытого общего) метода для каждого типа, с которым вызывается VerifyArgumentIsNotNull; микро-оптимизация, но редкий пример, когда общий не может быть предпочтительнее объекта старой школы.
Один из возможных недостатков вышеизложенного: я видел аналогичные реализации, где VerifyArgumentIsNotNull возвращает "значение". В этом случае требуется возвращающее значение типа T, чтобы избежать явного приведения. (IMO этот синтаксис уродливый, поэтому для меня это не является недостатком.)
Два других редакционных комментария:
1. Имя метода, которое я видел: ThrowIfNull более кратким, а "Throw" более явным, чем "Verify",
2. Я больше не использую для этого методы, потому что без аннотации в VerifyArgumentIsNotNull Resharper должен предположить, что аргумент все равно может быть нулевым. Мне гораздо проще дать R #, вставить 1-строчный if + throw, когда я добавлю NotNullAttribute.
Этот подход не работает для более широкого случая, когда вы хотите убедиться, что метод вызван с перечислимым. В этом случае дополнения Исала Табачника к аннотации велики.
Ответ 3
Предполагая, что вы используете Visual Studio 2013/2012 (я знаю только эту функцию в 2013 году), в окне анализа кода вы можете щелкнуть правой кнопкой мыши сообщение, чтобы перейти в "Подавить сообщение" > "В исходном файле или в подавлении" Файл
В качестве альтернативы вы можете добиться такого же эффекта, щелкнув раскрывающееся меню сообщения в окне анализа кода.