C #: как реализовать и использовать атрибуты NotNull и CanBeNull - PullRequest
39 голосов
/ 27 апреля 2009

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

Существует NotNullAttribute и CanBeNullAttribute в общих библиотеках Lokad , в пространстве имен Lokad.Quality.

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

[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 генерировать для меня предупреждения, если я попытаюсь отправить туда что-то, что является нулевым? Или это просто используется в какой-то среде тестирования? Или

Ответы [ 4 ]

46 голосов
/ 27 апреля 2009

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

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

Contract.RequiresAlways( x != null );

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

if ( x == null ) throw new ArgumentNullException("x");
Contract.EndContractBlock();
19 голосов
/ 27 апреля 2009

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

Что касается ReSharper, см. Аннотированная структура :

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

  • StringFormatMethodAttribute (для методов, которые принимают строки формата в качестве параметров)
  • InvokerParameterNameAttribute (для методов со строковыми литеральными аргументами, которые должны соответствовать одному из параметров вызывающей стороны)
  • AssertionMethodAttribute (для методов утверждения)
  • AssertionConditionAttribute (для параметров условия методов утверждения)
  • TerminatesProgramAttribute (для методов, которые завершают поток управления)
  • CanBeNullAttribute (для значений, которые могут быть нулевыми)
  • NotNullAttribute (для значений, которые не могут быть нулевыми)
8 голосов
/ 31 октября 2013

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

3 голосов
/ 01 декабря 2012

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

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

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

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

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

[AttributeUsage (AttributeTargets.Parameter)]

открытый абстрактный класс ParameterAttribute: Attribute

* * {Тысяча двадцать-один
public abstract void CheckParameter(ParameterInfo parameter, object value); 

}

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

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

[return: NonNull] public SomeObject SomeMethod ([NonNull] AnotherObject param1)

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

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

...