Могу ли я сказать C # обнуляемым ссылкам, что метод по сути является пустой проверкой на поле


14

Рассмотрим следующий код:

#nullable enable
class Foo
{
    public string? Name { get; set; }
    public bool HasName => Name != null;
    public void NameToUpperCase()
    {
        if (HasName)
        {
            Name = Name.ToUpper();
        }
    }
}

На Name = Name.ToUpper () я получаю предупреждение, что Name - это возможная нулевая ссылка, которая явно неверна. Я могу вылечить это предупреждение, вставив HasName, так что условие if (Name! = Null).

Есть ли какой-нибудь способ, которым я могу указать компилятору, что истинный ответ от HasName подразумевает ограничение не обнуляемости для Name?

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


1
ИМО вы должны использовать HasValueна обнуляемый тип, а не проверять его null. Это, вероятно, не влияет на вашу проблему, хотя.
Фредрик

Я думаю, что для вашего случая вы можете обернуть свой код #nullable disableпотом #nullable enableили restoreснова ( docs.microsoft.com/en-us/dotnet/csharp/… ).
GaryNg

5
Вы можете использовать !оператор "dammit" . if(HasName) { Name = Name!.ToUpper(); }
Ян Паоло Го

1
для многопоточного приложения имя может иметь значение NULL после проверки HasName, используя локальную переменную вместо того, чтобы возвращаться к свойству (кто знает, что свойство может делать в его геттере), что может привести к некоторым странным ошибкам (помните использование обработчика событий, где это произошло много раз)
XIU

Ответы:


3

Я осмотрел различные атрибуты System.Diagnostics.CodeAnalysisи не смог найти ничего подходящего, что очень разочаровывает. Самое близкое, что вы можете получить к тому, что вы хотите, это:

public bool TryGetName([NotNullWhen(true)] out string? name)
{
    name = Name;
    return name != null;
}

public void NameToUpperCase()
{
    if (TryGetName(out var name))
    {
        Name = name.ToUpper();
    }
}

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


2
Похоже, нам нужно больше атрибутов или что-то вроде утверждений машинописи
Стилгар

Я выберу это как ответ, потому что, как я и опасался, реальный ответ - «нет, C # пока не делает этого».
Джон Мелвилл

@JohnMelville Мне также не удалось найти предложение для такой функции, поэтому я не думаю, что мы можем ожидать, что это изменение произойдет в ближайшее время.
V0ldek

2
@XIU Компилятор уже слаб в этом аспекте. Если вы это сделаете if(Name != null) return Null.ToUpper(), не будет никакого предупреждения для нулевой разыменования, даже если технически это условие гонки TOCTOU. Я помню, как Мэдс Торгерсен говорил о том, как они это считали, но это сгенерировало бы столько ложных срабатываний, что вся функция ссылочных типов, обнуляемая, была бы практически бесполезна - 99% времени ваши свойства не будут изменены другим потоком. Поэтому все, что вам нужно сделать, - это создать атрибут, который будет проверять это свойство как проверку на нулевое значение в другом свойстве.
V0ldek

2
Я исправил проблему "не могу найти предложение по этому вопросу". ( github.com/dotnet/csharplang/issues/2997 ) Пожелайте мне удачи.
Джон Мелвилл

-10

String является ссылочным типом, а Nullable (например int?) является Nullable типами значений. Таким образом, вы не можете сделать это string? myString; Что вам нужно, это:

class Foo
{
    public string Name { get; set; }
    public bool HasName => !String.IsNullOrEmpty(Name);  ////assume you want empty to be treated same way as null
    public void NameToUpperCase()
    {
        if (HasName)
        {
            Name = Name.ToUpper();
        }
    }
}

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.