Обычно предупреждения о допустимости значений NULL можно подавить с помощью оператора, исключающего значение NULL (!). Я только что столкнулся с CS8670 — Инициализатор объекта или коллекции неявно разыменовывает возможный нулевой член и пытался подавить его с помощью оператора, исключающего нуль, однако это не сработало, или, точнее, я не знал, куда его поместить. Вот пример:
class Program {
public void M() {
var x = new A
{
// Warning is here, when initializing "Items"
Items = { "Hello", "World" }
};
}
}
class A {
public List<string>? Items { get; init;} = new List<string>();
}
Код для A
находится во внешней сборке, поэтому я не могу его изменить. Можно ли подавить CS8670 с помощью оператора, допускающего нулевое значение?
Несколько фрагментов информации, которые вы, возможно, захотите добавить к своему вопросу (поскольку мы не все запомнили коды предупреждений). 1) значение CS8670
и 2) строка, в которой возникает ошибка. Похоже, что первый - CS8670 - инициализатор объекта или коллекции неявно разыменовывает, возможно, нулевой член.
@Artur Я знаю, что это бессмысленно, но свойство находится во внешней сборке, и я не могу его изменить.
@ Flydog57 Спасибо за подсказку, я добавил ваши предложения.
@Artur, это может быть null - new A {Items = null};
, может быть, это правильный сценарий с точки зрения автора библиотеки (хотя я согласен - немного странно).
@GuruStron, ты прав
!
— это унарный постфиксный оператор, и кажется, что ATM нельзя использовать в этом конкретном случае, который в основном переводится в серию вызовов Add
(@sharplab):
A a = new A();
a.Items.Add("Hello");
a.Items.Add("World");
Вы можете попробовать использовать #nullable disable
:
var x = new A
{
#nullable disable
Items = { "Hello", "World" }
#nullable restore
};
Или просто создайте новый экземпляр списка:
var x = new A
{
Items = new(){ "Hello", "World" }
};
Лично «в общем случае» я бы выбрал второй вариант (если только в случае очень-очень чувствительного к производительности кода), потому что нет гарантии, что инициализация по умолчанию не будет удалена в какой-то момент автором библиотеки.
Если это разовый сценарий, то пара #nullable disable
/#nullable restore
, как упомянул @Guru, должна быть хорошей.
Другой вариант — отказаться от использования инициализатора коллекции и вместо этого получить доступ к Items
с помощью !
, за которым следует !
var x = new A();
x.Items!.Add("Hello");
x.Items!.Add("World");
// or
var items = x.Items!;
items.Add("Hello");
items.Add("World");
Если вы обнаружите, что это распространенный шаблон в вашем коде и считаете это решение неудобным, вы можете ввести оболочку вокруг этого класса, но я думаю, что это слишком много, чтобы обойти предупреждение об отсутствии значений. Так что делайте это только по мудрому суждению для вашего конкретного сценария:
using System;
using System.Collections.Generic;
// depending on how you are using "x", then var might work as well.
A x = new AWrapper
{
Items = { "Hello", "World" }
};
class A
{
public List<string>? Items { get; init; } = new List<string>();
}
public readonly struct AWrapper
{
private readonly A _a = new();
public AWrapper()
{
}
public List<string> Items => _a.Items!;
public static implicit operator A(AWrapper wrapper) => wrapper._a;
}
Это потому, что не имеет смысла помечать
Items
как nullable вместе сinit
и статической инициализацией. Никогда не может бытьnull
.