Может ли ненулевой ссылочный тип в C # 8 быть нулевым во время выполнения?

10

Мне кажется, на самом деле нет никакой гарантии, что ненулевая переменная никогда не будет иметь значение null. Представьте, что у меня есть класс с одним свойством, которое не может быть обнуляемым:

public class Foo
{
    public Foo(string test)
    {
        Test = test;
    }
    public string Test {get;set;}
}

Теперь может показаться, что теперь оно не может быть нулевым. Но если мы ссылаемся на этот класс с другой библиотекой, которая не использует обнуляемый контекст, ничто не мешает ему отправлять туда ноль.

Это правильно или есть некоторые проверки во время выполнения, а может быть, которые это обеспечивают?

Илья Черномордик
источник
Это public void Foo(string test){...}или public Foo(string test){...}?
huMpty duMpty
Спасибо, я исправил это. Вот что происходит, когда человек слишком полагается на R # для генерации конструкторов :)
Илья Черномордик
2
C # 9 (вероятно) добавит упрощенную проверку нуля .
Стивен
Короче говоря, функция «обнуляемые ссылочные типы» полностью не работает.
Алехандро

Ответы:

9

Вот что говорит MS ( https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/upgrade-to-nullable-references#interfaces-with-external-code ):

Компилятор не может проверять все вызовы ваших общедоступных API, даже если ваш код скомпилирован с включенными контекстами аннулируемых аннулируемых значений. Кроме того, ваши библиотеки могут быть использованы проектами, в которых еще не используются пустые ссылочные типы. Проверяйте входные данные для открытых API, даже если вы объявили их как необнуляемые типы.

Дмитрий Цой
источник
2

кто-то всегда может сделать

var myFoo = new Foo(null);

Может быть, вы можете использовать Domain Driven Design

public class Foo
{
    public Foo(string test)
    {
         if (string.IsNullOrWhiteSpace(test))
             throw new ArgumentNullException(nameof(test));

         Test = test;
    }
    public string Test {get;private set;}
}
humpty duMpty
источник
да, вы правы, я думаю, это всего лишь предупреждение. Я надеюсь, что в будущем они действительно смогут обеспечить его соблюдение, как, например, в Котлине
Илья Черномордик
2

Вы правы, другой код, который не использует новую функцию, может присвоить этому свойству значение null, нет никаких проверок во время выполнения, это просто подсказки для соответствия.

Вы всегда можете сделать это сами, если хотите проверить время выполнения:

public string Test { get; set{ if (value == null) throw new ArgumentNullException() } }

Обратите внимание, что вы можете гарантировать отсутствие значения null в большей части своего кода, вам просто нужно добавить защиту в ваш публичный API верхнего уровня и убедиться, что классы должным образом запечатаны и т. Д.

Конечно, люди все еще могут использовать рефлексию, чтобы прокрутить ваш код, но тогда это на них

Milney
источник
Таким образом, это фактически означает, что я все еще могу получить исключение Null Reference, даже если я использую ненулевой тип, верно?
Илья Черномордик
Ну ... вы не можете в коде, который вы компилируете, потому что у вас есть подсказки ... но код других людей, на которые нет подсказок, но ссылаются на ваш код - да, они могут получить нулевое исключение
Милни
Что ж, если, например, автомаппер использует ваш конструктор или что-то в этом роде, это все равно вы, кто получит исключение :)
Илья Черномордик
Of course people can still use reflection to f*** your code upправда, правда так и есть. Вы определенно можете использовать рефлексию, чтобы сделать это, рекомендуется , нет , люди все еще делают это, да.
Çöđěxěŕ
2

Даже в вашем собственном коде, если вы решите сделать это, вы можете передать null, используя оператор NULL. null!считается ненулевым, поскольку анализ компилятора обнуляется.

Damien_The_Unbeliever
источник
-1

Чтобы справиться с нулевыми проверками, а также сделать ваш код читабельным, я предлагаю шаблон Null Object Design.

Больше читать здесь:

https://www.c-sharpcorner.com/article/null-object-design-pattern/

По сути, это включает в себя создание нового объекта, который получен из того же интерфейса и имеет нулевой экземпляр.

Пример:

public class NullExample : IExample  
{  
    private static NullExample _instance;  
    private NullExample()  
    { }  

    public static NullExample Instance  
    {  
        get {  
            if (_instance == null)  
                return new NullExample();  
            return _instance;  
        }  
    }  

    //do nothing methods  
    public void MethodImplementedByInterface1()  
    { }  

    public void MethodImplementedByInterface1()  
    { }  
}  

Нулей нельзя избежать, однако их можно проверить чисто.

Gauravsa
источник