Решение с простым кодом
Вы всегда можете создать структуру, которая помогает отлавливать ошибки нулевых ссылок ранее, помечая переменные, свойства и параметры как «не обнуляемые». Вот пример, концептуально смоделированный после того, как Nullable<T>
работает:
[System.Diagnostics.DebuggerNonUserCode]
public struct NotNull<T> where T : class
{
private T _value;
public T Value
{
get
{
if (_value == null)
{
throw new Exception("null value not allowed");
}
return _value;
}
set
{
if (value == null)
{
throw new Exception("null value not allowed.");
}
_value = value;
}
}
public static implicit operator T(NotNull<T> notNullValue)
{
return notNullValue.Value;
}
public static implicit operator NotNull<T>(T value)
{
return new NotNull<T> { Value = value };
}
}
Вы будете использовать очень похоже на то же самое, что и Nullable<T>
, за исключением того, что вы хотите сделать прямо противоположное - не допустить null
. Вот несколько примеров:
NotNull<Person> person = null; // throws exception
NotNull<Person> person = new Person(); // OK
NotNull<Person> person = GetPerson(); // throws exception if GetPerson() returns null
NotNull<T>
неявно преобразуется в T
, поэтому вы можете использовать его где угодно. Например, вы можете передать объект Person
методу, который принимает NotNull<Person>
:
Person person = new Person { Name = "John" };
WriteName(person);
public static void WriteName(NotNull<Person> person)
{
Console.WriteLine(person.Value.Name);
}
Как вы можете видеть выше, при использовании nullable вы можете получить доступ к базовому значению через свойство Value
. Кроме того, вы можете использовать явное или неявное приведение, вы можете увидеть пример с возвращаемым значением ниже:
Person person = GetPerson();
public static NotNull<Person> GetPerson()
{
return new Person { Name = "John" };
}
Или вы даже можете использовать его, когда метод просто возвращает T
(в данном случае Person
), выполняя приведение. Например, следующий код будет таким же, как и код выше:
Person person = (NotNull<Person>)GetPerson();
public static Person GetPerson()
{
return new Person { Name = "John" };
}
Комбинация с удлинителем
Объедините NotNull<T>
с методом расширения, и вы сможете охватить еще больше ситуаций. Вот пример того, как может выглядеть метод расширения:
[System.Diagnostics.DebuggerNonUserCode]
public static class NotNullExtension
{
public static T NotNull<T>(this T @this) where T : class
{
if (@this == null)
{
throw new Exception("null value not allowed");
}
return @this;
}
}
А вот пример того, как его можно использовать:
var person = GetPerson().NotNull();
GitHub
Для справки, я сделал код выше доступным на GitHub, вы можете найти его по адресу:
https://github.com/luisperezphd/NotNull