C# не принимает значение null для параметра `params object?[] values`

У меня есть параметр, определенный так: params object?[] values, и я не могу отправить null (т.е. я хотел бы иметь массив с одним null внутри).

Он работает без параметров.

Ошибка: Cannot convert null literal to non-nullable reference type.

public class Foo
{
    private void DoesNotWork(params object?[] values)
    {
    }
    
    private void DoesWork1(object? value)
    {
    }
    
    private void DoesWork2(object?[] values)
    {
    }

    public void Test()
    {
        DoesNotWork(null);
        DoesWork1(null);
        DoesWork2(new object?[] { null });
    }
}

Я что-то не так делаю или компилятор накладывает какие-то ограничения?

P.S. Это также работает, если метод «DoesNotWork» из библиотеки, в которой не включено значение nullable, то есть он определен так: DoesNotWork(params object[] values), поэтому я могу отправить туда null.

П.П.С. Я обнаружил, что этот обходной путь также работает: DoesNotWork((object?) null);.

П.П.П.С. DoesNotWork(null!); тоже работает

Отвечает ли это на ваш вопрос? Какой тип нулевого литерала?

phuzi 03.05.2023 10:01

Я не вижу там ответа на свой вопрос или я что-то упускаю. Как видите, совершенно нормально отправлять значение null в параметр без «параметров». Итак, без параметров С# может привести к объекту значение null? видимо

Ilya Chernomordik 03.05.2023 10:02

Нет способа отличить передачу нулевого массива от массива с 1 нулевым значением? Когда вы ставите (object?)null, C# теперь может понять, что вы имели в виду object[]{ null }, а не (object?[])null

phuzi 03.05.2023 10:07

Ну, сам массив не обнуляемый, это только элементы массива. Итак, кажется, есть простой способ отличить? Кроме того, он работает, когда метод находится в библиотеке, которая игнорирует нули. т.е. компилятор может точно отличить, что это первый элемент массива объектов

Ilya Chernomordik 03.05.2023 10:10
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
63
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

object тип по умолчанию не обнуляемый.

Вы можете вызывать свои методы, например

DoesNotWork((object?)null);

В качестве альтернативы, если вы измените метод, например

private void DoesWork(params object[]? values)
{
}

Вы могли бы просто назвать это как DoesWork(null);

Ответ принят как подходящий

вы получаете сообщение об ошибке, поскольку единственный предоставленный параметр имеет значение null, компилятор отправит значение null вместо создания массива с предоставленными параметрами:

DoesNotWork(null); // creates no array
DoesNotWork((object?)null); // creates array with one null element
DoesNotWork(null, null); // create array with two null elements

если бы вы изменили подпись метода на: void DoesNotWork(params object?[]? values) тогда вы не получите предупреждение, или вы подавите предупреждение с помощью !, как вы это сделали

Я вижу, меня на самом деле обманули, заставив думать, что когда я использовал библиотечный метод, он действительно создал массив с одним нулевым элементом, хотя на самом деле это был «нулевой массив», который просто обрабатывался, чтобы сделать то же самое в библиотеке. Таким образом, выполнение object?[]? values действительно будет имитировать то же поведение, что и для object[] values без возможности обнуления. R# даже показывает, что когда я отправляю, например. (1) это params values, но (null) просто values.

Ilya Chernomordik 03.05.2023 10:15

Хотя теоретически С# мог бы различать, что «нуль» должен быть элементом массива (так же, как, например, 1), если сам массив не может быть нулевым.

Ilya Chernomordik 03.05.2023 10:17

Да, я думаю, что компилятор может определить, что массив не имеет значения NULL, а затем предоставить массив с одним нулевым элементом, но это не тот случай, когда ссылки, допускающие значение NULL, отключены, следовательно, это поведение по умолчанию imo.

Florent Bunjaku 03.05.2023 10:22

Да, понятно, спасибо за хороший и разъясняющий ответ!

Ilya Chernomordik 03.05.2023 10:23

null рассматривается как необнуляемый ссылочный тип.

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

DoesNotWork((object?[])null).

public class Foo
{
    private void DoesNotWork(params object?[] values)
    {
    }
    
    private void DoesWork1(object? value)
    {
    }
    
    private void DoesWork2(object?[] values)
    {
    }

    public void Test()
    {
        DoesNotWork((object?[])null);
        DoesWork1(null);
        DoesWork2(new object?[] { null });
    }
}

Другие вопросы по теме