Чи можу я сказати C # зворотним посиланням, що метод фактично є нульовою перевіркою на полі


14

Розглянемо наступний код:

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

На ім'я = ім'я. Ім'я. Tooper () я отримую попередження про те, що Ім'я - це можлива нульова посилання, що явно невірно. Я можу вилікувати це попередження, вставивши HasName, тому умовою є if (Name! = Null).

Чи є якийсь спосіб я доручити компілятору, що справжня відповідь від HasName передбачає обмеження, яке не стосується нуля?

Це важливо, тому що HasName може насправді перевірити набагато більше речей, і я можу захотіти використовувати його в декількох місцях, або це може бути публічна частина поверхні API. Є багато причин, які хочуть врахувати нульову перевірку на її власний метод, але це, мабуть, порушує контрольну контрольну систему.


1
ІМО, який ви повинні використовувати HasValueдля нульового типу, не перевіряти null. Це, мабуть, не впливає на вашу проблему.
Фредрік

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

5
ви можете скористатися !оператором "чорт" . if(HasName) { Name = Name!.ToUpper(); }
Ян Паоло Ідіть

1
для багатопотокового додатку, ви можете мати ім'я "null" після перевірки HasName, використовуючи змінну локально, замість того, щоб повернутися до ресурсу (хто знає, що може зробити власність у його getter), збирається видавати кілька прикольних помилок (пам’ятайте використання обробника подій, де це траплялося багато)
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
Здається, нам потрібно більше атрибутів або щось на зразок тверджень машинопису
Stilgar

Я виберу цю як відповідь, оскільки, схоже, справжня відповідь, як я побоювався, «ні, c # ще не робить цього».
Джон Мелвіл

@JohnMelville Я також не зміг знайти пропозицію щодо такої функції, тому я не думаю, що ми можемо очікувати цього зміни незабаром.
V0ldek

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

2
Я вирішив проблему "не можу знайти пропозицію щодо цієї проблеми". ( github.com/dotnet/csharplang/isissue/2997 ) Побажайте мені удачі.
Джон Мелвіл

-10

Рядок - це еталонний тип, а нульовий (наприклад int?) - тип нульового значення. Тож ви справді цього не можете зробити 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.