Страница галереи Resharper
История изменений
Основная идея этого расширения состоит в том, чтобы изменить поведение статического анализа ненурируемости Resharper, чтобы конкретные элементы кода получали аннотацию нуля по умолчанию без указания явного атрибута [NotNull] или [CanBeNull] . Например, эталонные типы в параметрах метода по умолчанию [NotNull] (→ они нуждаются в явном [CanBeNull] , чтобы стать нулевым).

При включении неявной нуляемости для конкретных, настраиваемых, синтаксических элементов применяются следующие правила.
[NotNull] .[CanBeNull] .null значением по умолчанию неявно [CanBeNull] .Короче говоря, код показал на картинке выше ...
public string Bar ( string a , [ CanBeNull ] string b , string c = null )
{
// ...
}... неявно становится ...
[ NotNull ]
public string Bar ( [ NotNull ] string a , [ CanBeNull ] string b , [ CanBeNull ] string c = null )
{
// ...
}[NotNull] как дефолт Без этого расширения значение нулевой по умолчанию «неизвестно», что означает, что Resharper исключает эти элементы для анализа его нуля. В результате измененной нуляемости по умолчанию этого расширения мы должны разместить аннотации [CanBeNull] только для конкретных элементов кода (например, параметр типа ссылки, где его следует разрешить передавать null в качестве аргумента) и не нуждаются в явных аннотациях для большинства случаев (в базах кода, которые пытаются уменьшить передачу null ссылок на минимум).
Resharper 9.2 ввел поддержку анализа нуля для методов async ( Task<T> return typed). При включении неявной нуляемости для возвращающих значений метода Task<T> возвращаемые методы также становятся косвенно [ItemNotNull] (Resharper использует этот атрибут для обозначения значения Task<T> ). Для нулевой Task<T> возвращают значения, это может быть переопределено [ItemCanBeNull] .
Следующий пример программы содержит потенциальное NullReferenceException в command.Equals("Hello") , потому что программист пропустил, что GetCommand() также может вернуть null .
public static void Main ( string [ ] args )
{
string command = GetCommand ( args ) ;
if ( command . Equals ( "Hello" ) )
Console . WriteLine ( "Hello World!" ) ;
}
private static string GetCommand ( string [ ] args )
{
if ( args . Length < 1 )
return null ;
return args [ 0 ] ;
}При включении неявной нуляки эта ошибка была бы обнаружена статическим анализом Resharper.
null в GetCommand() потому что этот метод будет неявно аннотирован как [NotNull] .[CanBeNull] в GetCommand() .[CanBeNull] , Resharper теперь предупредил бы о потенциальном NullReferenceException в command.Equals("Hello") Call in Main() . В приведенном выше примере неявная нуляемость заставляет программиста исправить отсутствующий атрибут [CanBeNull] на GetCommand() . Это показывает, как число аннотаций [CanBeNull] будет увеличено в базе кода и, следовательно, не только улучшает статический анализ Resharper, но и документацию подписей метода (контракты).
Другая цель этого расширения - привлечь статический анализ Resharper в синхронизации с неявными нулевыми проверками Fody Nullguard. Например, эти инъекции Fody Weaver throw new ArgumentNullException(/*...*/) .. Другими словами, этот ткач добавляет проверки времени выполнения , чтобы нультироваться статический анализ RESHARPER.
C# 8 получит нулевые типы ссылок , которые приносят типы опций на язык C#. Это соответствует семантике неявной нуляции и идет еще дальше, потому что он распространяет ее на местные жители, общие параметры, ... потому что аннотация нуля работает на уровне типа.
[ CanBeNull ]
string Bar ( [ CanBeNull ] string a , string b )
{
string result = a ;
return result ;
}... затем соответствует ...
string ? Bar ( string ? a , string b )
{
string ? result = a ;
return result ;
} Это сделает неявную нулевую ненужную в будущем и в то же время является идеальным «пути обновления», потому что хорошая кодовая база [CanBeNull] будет легко переносимой для C# 8.
С момента версии 2016.1 Resharper поддерживает (в «внутреннем режиме») сопоставимая функция (см. Инспекцию кода | Настройки ) со следующими различиями.
Неявная нуляция ...
[NotNull] . Явные или неявные типы элементов [NotNull] выделены пунктирным подразделением. (См. Розовый подчеркивает подчеркивание в Bar -методе на примерном снимке экрана.) Это помогает распознать все элементы [NotNull] , особенно предполагаемые элементы [NotNull] из базового класса и элементов кода, которые настроены как неявно [NotNull] .
Выделение может быть включено/отключено на странице «Параметры неявной нулевой» , а цвета можно настроить в параметрах Visual Studio «Шрифты и цвета».
Неявная нуляция может быть включена или отключена для конкретных синтаксических элементов в проверке кода | Страница параметров неявных параметров .

Неявная нуляемость также может быть настроена с помощью кода с использованием AssemblyMetadataAttribute . Это имеет преимущество в том, что конфигурация собирается в сборку, так что потребители сборки с установленной неявной нуляемостью получали те же аннотации неявных аннулируемости скомпилированных элементов кода, что и в решении библиотеки.
Пример:
[ assembly : AssemblyMetadata ( "ImplicitNullability.AppliesTo" ,
"InputParameters, RefParameters, OutParametersAndResult, Fields, Properties" ) ]
[ assembly : AssemblyMetadata ( "ImplicitNullability.Fields" , "RestrictToReadonly" ) ]
[ assembly : AssemblyMetadata ( "ImplicitNullability.Properties" , "RestrictToGetterOnly" ) ]
[ assembly : AssemblyMetadata ( "ImplicitNullability.GeneratedCode" , "Exclude" ) ]В дополнение к изменению поведения анализа нуля, следующие предупреждения о проверке кода предоставляются этим расширением.
Для получения дополнительной информации об этих предупреждениях (и их мотивации) см. Их описание в проверке кода Resharper | Страница вариантов тяжести проверки .
ID: ImplicitNotNullConflictInHierarchy
abstract class Base
{
public abstract void Method ( [ CanBeNull ] string a ) ;
}
class Derived : Base
{
// "Implicit NotNull conflicts with nullability in base type":
public override void Method ( string a )
{
}
} ID: ImplicitNotNullElementCannotOverrideCanBeNull
abstract class Base
{
[ CanBeNull ]
public abstract string Method ( ) ;
}
class Derived : Base
{
// "Implicit NotNull element cannot override CanBeNull in base type, nullability should be explicit":
public override string Method ( ) => "" ;
} IDS: ImplicitNotNullOverridesUnknownBaseMemberNullability Sprop. ImplicitNotNullResultOverridesUnknownBaseMemberNullability
class Derived : External . Class /* (external code with unannotated 'Method' and 'Function') */
{
// "Implicit NotNull overrides unknown nullability of base member, nullability should be explicit":
public override void Method ( string a )
{
}
// "Implicit NotNull result or out parameter overrides unknown nullability of base member,
// nullability should be explicit":
public override string Function ( ) => "" ;
} ID: NotNullOnImplicitCanBeNull
// "Implicit CanBeNull element has an explicit NotNull annotation":
void Foo ( [ NotNull ] int ? a )
{
} Большое спасибо Фабиану Шмиду за поддержку дизайна и концепции неявной нуль .