Если вы используете ReSharper, то вы, наверняка, знакомы с его подсветкой "Possible 'NullReferenceException'". В этой статье я кратко расскажу об анализаторе, который выводит предупреждения такого рода, и о том, как ему помочь делать это лучше. Сразу рассмотрим пример: ReSharper справедливо подсветит iAmNullSometimes во второй строке метода с таким предупреждением. Теперь выделим метод: После этой операции предупреждение пропадает. Почему так происходит? Анализатор пытается выявить, какие значения могут иметь используемые переменные. Уточню, до какого уровня абстракции сокращено знание о значении переменной. С точки зрения анализатора переменная может иметь одно или несколько состояний: В результате работы анализатора для каждой точки использования переменных определяется набор возможных их состояний.  В первом листинге iAmNullSometimes после инициализации будет иметь два возможных состояния: NULL и NOT_NULL. Поэтому подсветка "Possible NullReferenceException" говорит нам, что есть хотя бы один путь выполнения программы, в котором iAmNullSometimes будет иметь значение null (в данном случае путь, в котором condition ложно).  Второй случай сложнее. Анализатор не знает, какие значения возвращает GetNullWhenFalse. Конечно, можно его проанализировать и убедиться, что он может вернуть null. Но при увеличении числа методов, которые тоже что-то вызывают, время, затрачиваемое на такой анализ, не позволяет использовать анализатор "на лету" на современных PC (чтобы ReSharper смог установить подсветки возможных ошибок). Тем более, вызываемый метод может оказаться в библиотеке, на которую ссылается наш проект. Не будем же мы ее так же "на лету" ее декомпилировать и анализировать. Есть еще один вариант. Предполагать, что внешние методы, о которых ничего не известно, возвращают либо NULL, либо NOT_NULL. Так работает пессимистичный анализ. В ReSharper по-умолчанию используется оптимистичный анализ. В нем, если о методе ничего не известно, то возвращаемое значение будет в специальном состоянии UNKNOWN. Переменная, оказавшаяся в этом состоянии к моменту ее использования, не подсвечивается (если, конечно, нет других путей на которых null ей был присвоен явно или из CanBeNull-метода). Во втором листинге это и заставляет анализатор "потерять бдительность". Анализатор и его режимы работы требуют отдельной статьи, поэтому о них я напишу отдельно. Как в случае оптимистичного, так и пессимистичного анализа все-таки хочется как-то знать, на что способен вызываемый метод, чтобы ReSharper находил больше потенциальных ошибок. Тут нам на помощь приходят контракты. Анализатор ReSharper'a может использовать дополнительные знания о вызываемых методах, получая его через контракты вида "метод никогда не возвращает null", "метод может вернуть null", "в параметр нельзя подставить null". В простейшем случае эти контракты задаются с помощью атрибутов JetBrains.Annotations.CanBeNullAttribute и JetBrains.Annotations.NotNullAttribute. Применение атрибута к методу будет говорить о том, может ли он возвращать null. К параметру — о допустимости подстановки нулевого значения. Также их можно применять к свойствам и полям. Эти атрибуты определены в библиотеке JetBrains.Annotations.dll, которая лежит в <ReSharper install directory>\Bin.  Пример, приведенный во втором листинге, можно улучшить, пометив метод GetNullWhenFalse атрибутом CanBeNull: При использовании метода переменной iAmNullSometimes в таком случае появляется подсветка "Possible 'NullReferenceException'". Если вам не хочется в своем проекте тянуть за собой дополнительную сборку, которая к тому же не добавляет функциональности в рантайме, то вы можете объявить эти атрибуты прямо в своем проекте. Анализатору подойдет использование любых атрибутов из любых сборок, лишь бы их имена совпадали с теми, которые указаны в JetBrains.Annotations.dll. Определения этих атрибутов можно легко получить с помощью кнопки Copy default implementation to clipboard, расположенной на одной из страниц настроек ReSharper'a: Если вам хочется использовать внешнюю библиотеку (например mscorlib.dll), прописывание контрактов для ее сущностей с помощью атрибутов не представляется возможным. Тут на помощь приходят External Annotations. Эта фича ReSharper позволяет дополнять уже скомпилированные сущности атрибутами используемыми анализатором ReSharper'a. External Annotations дают возможность "обмануть" анализатор — сделать так, чтобы он видел у методов, параметров и других объявлений атрибуты, которые не были объявлены при компиляции библиотеки. Для этого атрибуты нужно прописать в XML-файле, расположенном в директории <ReSharper install directory>\Bin\ExternalAnnotations. Так определены контракты для стандартных библиотек, которые попадают в эту папку при установке ReSharper. Эти контракты были выведены в результате анализа исходных кодов и Microsoft Contracts. Контракты, полученные в результате первого подхода расположены в файлах с именами .Generated.xml, в результате второго — в .Contracts.xml. Файлы, описывающие дополнительные атрибуты, имеют структуру, похожую на структуру XmlDoc-файлов. Например, для метода XmlReader.Create(Stream input) из сборки System.Xml четвертого фреймворка контракты NotNull задаются так: Чтобы ReSharper подхватил файл, его нужно разместить одним из следующих способов: <ReSharper install directory>\Bin\ExternalAnnotations\<Assembly name>.xml или <ReSharper install directory>\Bin\ExternalAnnotations\<Assembly name&gt\<Any name>.xml, где <Assembly name&gt — имя сборки без указания версии. Если располагать файлы вторым способом, то для одной сборки можно указать несколько наборов контрактов. Это может быть необходимо для различия контрактов сборок с разными версиями. Сейчас редактирование этих файлов не очень удобно и подразумевает много ручной работы, для которой к тому же необходимы права администратора. Но в скором будущем планируется выход в свет инструмента, упрощающего эту работу. Скорее всего он будет оформлен в виде плагина к ReSharper'у. Несколько практик применения External Annotations, улучшающих жизнь при работе с ReSharper'ом. Аннотация CanBeNull для этого метода довольно часто является темой для баг-репортов. Дело в том, что SelectNodes является методом класса XmlNode и в общем случае может вернуть null (например для XmlDeclaration). Но чаще всего мы используем этот метод, когда он никогда не возвращает null, — из XmlDocument. Одним из решений может быть удаление соответствующей аннотации из External Annotations или замена ее на NotNull. Но можно поступить и корректнее, написав extension method для XmlDocument: В данном случае, конечно, было бы хорошо еще сделать методы вида SelectElements и SelectAttributes, чтобы избежать преобразования типов каждый раз, но это уже другая история. Если вы используете в своем проекте собственные (или сторонних производителей) методы Assert, то их можно пометить атрибутами AssertionMethodAttribute и AssertionConditionAttribute. Прямые кандидаты на такую пометку — это методы Contracts.Assert, если вы используете Microsoft Contracts: А еще можно посмотреть в сторону TerminatesProgramAttribute, если у вас есть методы, которые всегда бросают исключение.