C#: как реализовать и использовать атрибуты NotNull и CanBeNull

Я хочу, чтобы программисты и я знали, что метод не хочет null, и если вы все равно отправите ему null, результат будет некрасивым.

В Общих библиотеках Lokad в пространстве имен Lokad.Quality есть NotNullAttribute и CanBeNullAttribute.

Но как это работает? Я посмотрел исходный код этих двух атрибутов, и он выглядит так:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter |
                AttributeTargets.Property | AttributeTargets.Delegate |
                AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
[NoCodeCoverage]
public sealed class NotNullAttribute : Attribute
{
}

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter |
                AttributeTargets.Property | AttributeTargets.Delegate |
                AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
[NoCodeCoverage]
public sealed class CanBeNullAttribute : Attribute
{
}

Два пустых класса, наследующие от Attribute. Как они используются? Вам нужно искать xml-документацию и знать, что она там есть? Потому что я пытался сделать свою собственную копию атрибута и использовать версию Lokad, но когда я попытался отправить нуль напрямую, я не получил никакого сообщения. Ни от ReSharper, ни от VS. Чего я, собственно, и ожидал. Но как они используются? Могу ли я каким-то образом заставить VS генерировать для меня предупреждения, если я попытаюсь отправить туда что-то пустое? Или он просто используется в какой-то среде тестирования? Или?


person Svish    schedule 27.04.2009    source источник
comment
Чтобы прокомментировать ваш конкретный случай, эти атрибуты ничего не делают и являются просто документацией. Однако другие ответы дают хорошие альтернативы.   -  person Sander    schedule 27.04.2009
comment
Nullable - лучшее имя для CanBeNull, просто говорю :)   -  person Ahmet Alp Balkan    schedule 28.03.2013


Ответы (4)


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

(редактировать) пример:

Contract.RequiresAlways( x != null );

Все просто... механизм кодовых контрактов работает на уровне IL, поэтому он может анализировать это и выдавать предупреждения/ошибки при вызове кода во время сборки или во время выполнения. Для обратной совместимости, если у вас есть существующий код проверки, вы можете просто указать ему, где заканчивается проверка работоспособности, и он сделает все остальное:

if ( x == null ) throw new ArgumentNullException("x");
Contract.EndContractBlock();
person Marc Gravell    schedule 27.04.2009
comment
Это выглядело очень гладко! Будет ли это работать и в VS 2008? Что вы подразумеваете под более интегрированным? - person Svish; 27.04.2009
comment
Да; ссылки, которые я разместил, были для варианта VS2008. Под более интегрированным я подразумеваю, что, насколько мне известно, он встроен в IDE и среду выполнения, а не является отдельным дополнением. Я не проверял (действительно, не могу), но это может означать, что он работает и в Express Edition (надстройка не работает). - person Marc Gravell; 27.04.2009
comment
Прохладно. Вы уже пробовали это дополнение? Легко установить и использовать? Безопасно ли использовать в производственной среде? (Убьют ли меня другие сотрудники, если я его добавлю? :P) - person Svish; 27.04.2009
comment
Я только что запустил свою старую сборку CTP VS2010, но похоже, что биты не были готовы, когда вышел последний CTP. Вот что, я попробую и узнаю ;-p - person Marc Gravell; 27.04.2009
comment
Выглядит вполне пригодным для использования. Вы включаете его, добавляя ссылку на Microsoft.Contracts.dll и устанавливая флажок на вкладке Coer Contracts свойств проекта. Статическая проверка предназначена для сообщений времени сборки. - person Marc Gravell; 27.04.2009
comment
Я получаю этот Coer Contracts, когда устанавливаю это дополнение? Это нужно будет сделать на всех машинах, которые будут использовать это решение, верно? Как насчет развертывания? Что Microsoft.Contracts.dll по умолчанию не входит в .Net Framework? - person Svish; 27.04.2009
comment
Только в .NET 4.0, нет. Однако, если вы настроите использовать контракты только для отладочных сборок, вам может не понадобиться его развертывание. И если вам нужны проверки во время выполнения, я ожидаю, что вы можете просто развернуть dll для поддержки во время выполнения. Установка предназначена в первую очередь для целей Visual Studio. - person Marc Gravell; 27.04.2009
comment
Но если я начну использовать эту Microsoft.Contracts.dll, когда выйдет .NET 4.0, нужно ли будет прекратить ссылаться на мою локальную копию Microsoft.Contracts.dll? Или было бы больше работы, чтобы портировать это? - person Svish; 27.04.2009
comment
Насколько я понимаю, классы/пространства имен и т. д. одинаковы - меняется только сборка. Таким образом, в версии 4.0 вы просто удаляете дополнительную ссылку (никаких других изменений). Но так как 4.0 это предварительная бета... - person Marc Gravell; 27.04.2009
comment
Обратите внимание, что контракты кода похоже, потеряли популярность в VS 2017. - person jrh; 19.09.2017

Это можно сделать либо с помощью AOP, посредством чего Advice во время выполнения проверяет, является ли параметр метода null и допустимы ли значения NULL. См. PostSharp и Spring. .NET для АОП.

Что касается ReSharper, см. раздел Аннотированная платформа:

Мы проанализировали большую часть библиотеки классов .NET Framework, а также NUnit Framework и аннотировали ее с помощью внешних XML-файлов, используя набор настраиваемых атрибутов из пространства имен JetBrains.Annotations, а именно:

  • StringFormatMethodAttribute (для методов, которые принимают строки формата в качестве параметров)
  • InvokerParameterNameAttribute (для методов со строковыми аргументами, которые должны соответствовать одному из параметров вызывающего объекта)
  • AssertionMethodAttribute (для методов утверждений)
  • AssertionConditionAttribute (для параметров условий методов утверждений)
  • TerminatesProgramAttribute (для методов, завершающих поток управления)
  • CanBeNullAttribute (для значений, которые могут быть нулевыми)
  • NotNullAttribute (для значений, которые не могут быть нулевыми)
person Anton Gogolev    schedule 27.04.2009
comment
Вы можете получить аннотации ReSharper от NuGet: nuget.org/packages/JetBrains.Annotations - person aboy021; 22.08.2013
comment
Но аннотации resharper — это просто комментарий, читаемый resharper. Они не проверяются во время выполнения. - person Revious; 06.03.2015
comment
Ваша ссылка больше не указывает на цитируемый текст, цитируемый текст был перемещен в Внешние аннотации, хотя, поскольку OP аннотирует свой собственный код, внешние аннотации не подходят. - person Jade; 14.04.2018

Эти аннотации предназначены для ReSharper и скопированы из пространства имен JetBrains.Annotations. Фреймворк может поместить их в собственное пространство имен, однако ReSharper НЕ будет автоматически подбирать эти аннотации — вам нужно указать ReSharper использовать пользовательское пространство имен в диалоговом окне параметров. Как только вы выберете новое пространство имен, анализ ReSharper подберет атрибуты и выдаст вам основные моменты и предупреждения.

person citizenmatt    schedule 31.10.2013

Как указал Антон Гоголев, атрибуты можно создавать с помощью PostSharp (обратите внимание, что CodeContract использует статические вызовы методов внутри тела метода)

ОБНОВЛЕНИЕ, февраль 2013 г.: новая версия PostSharp 3.0 (в настоящее время находится в стадии бета-тестирования) будет поддерживать Проверка параметров, полей и свойств

1) Статья validate-parameters-using-attributes имеет реализацию

открытый класс NotEmpty : ParameterAttribute

открытый класс NotNull: ParameterAttribute

[AttributeUsage(AttributeTargets.Parameter)]

общедоступный абстрактный класс ParameterAttribute : Атрибут

{

public abstract void CheckParameter(ParameterInfo parameter, object value); 

}

Также требуется атрибут метода с аспектом границы метода для обработки атрибутов параметра.

2) В комментарии к статье есть ссылки на очень похожую реализацию для NonNull/NonEmpty

[возврат: NonNull] public SomeObject SomeMethod([NonNull] AnotherObject param1)

Исходный код находится в коде Google Torch/DesignByContract.

3) еще один более сложный пример описан на http://badecho.com/2011/11/validating-method-parameters-with-postsharp/

person Michael Freidgeim    schedule 01.12.2012