Укажите NotNull, если метод возвращается вообще - PullRequest
3 голосов
/ 08 октября 2019

Я использую новые обнуляемые ссылочные типы из C # 8, и мне было интересно, можно ли указать, что передаваемый параметр не равен NULL, если метод вообще возвращает.

Я нашел[NotNullIf] и [DoesNotReturnIf], но, похоже, они запускают возвращаемое значение метода и конкретный параметр bool соответственно.

Вот что у меня сейчас есть:

public static bool RaiseIfNull([NotNullWhen(true)] object? thing) => RaiseIf(() => thing is null);
public static bool RaiseIf(Func<bool> predicate)
{
  if (predicate()) throw new HttpException(400);
  return true;
}

Это кажетсяхорошо, но потом, когда я это называю - я все равно вижу предупреждения. (Я также попробовал RaiseIfNull([NotNullIfNotNull("thing")] object? thing), и это не сработало.)

[HttpPost("{id}")]
public async Task Etc(string id, [FromBody] Dto data)
{
  HttpException.RaiseIfNull(data?.property);
  await DoEtc(id, data.property)); // warning here
}

Я что-то упускаю из виду?

1 Ответ

2 голосов
/ 08 октября 2019

Использование обычной нулевой проверки

Прежде всего, RaiseIfNull не предлагает чего-то большего, чем:

var value=data?.property ?? new HttpException(400);

, которые может распознавать компилятор,RaiseIfNull с другой стороны, скрывает, что на самом деле происходит. Этот код не выдает предупреждение:

class D
{
    public string? property{get;set;}
}


D? data=null;
var value=data?.property ?? throw new HttpException(400);
Console.WriteLine(value.Length);

Безусловное постусловие и обобщения

Тем не менее, правильный аргумент для использования - NotNull - после выполнения метода параметр не имеет значение NULL, даже если сам тип имеет значение NULL. Этот атрибут может применяться к:

  • Параметры
  • Свойства
  • Поля и
  • Возвращаемые значения

Методы также могут быть сделаны универсальными, чтобы избежать объединения структур в объекты. Чтобы сделать это, нам нужно указать, является ли тип классом или структурой, потому что результирующие конкретные типы сильно отличаются - string? все еще является строкой, а int? является Nullable<int>:

public static bool RaiseIfNull<T>([NotNull] T? thing) 
    where T:class
    => RaiseIf(() => thing is null);

public static bool RaiseIfNull<T>([NotNull] T? thing) 
    where T:struct
    => RaiseIf(() => thing is null);

С учетом этих методов следующий код также не будет выдавать предупреждение:

D? data=null;
RaiseIfNull(data?.property);
Console.WriteLine(data.property.Length);

Наконец, мы можем избавиться от возвращаемого значения:

public static void RaiseIfNull<T>([NotNull] T? thing) 
    where T:class
    => RaiseIf(() => thing is null);

public static void RaiseIfNull<T>([NotNull] T? thing) 
    where T:struct
    => RaiseIf(() => thing is null);
...