Що ?[]? синтаксис в C #?


85

У той час як я вивчав делегат , який є на самому ділі це абстрактний клас Delegate.cs, я побачив наступний метод , в якому я не розумію

  • Чому значення повернення використовується, ?хоча це вже тип посилання ( класу )
  • ?[]? значення параметра

Чи можете ви пояснити?

public static Delegate? Combine(params Delegate?[]? delegates)
{
    if (delegates == null || delegates.Length == 0)
        return null;

    Delegate? d = delegates[0];
    for (int i = 1; i < delegates.Length; i++)
        d = Combine(d, delegates[i]);

    return d;
}


23
Хіба це не зведений масив, який може містити нульові значення?
Cid

3
c # 8, тепер ви можете вказати, що змінна об'єкта не може бути нульовою. Якщо ви перегортаєте цей прапор компілятора, вам потрібно вказати кожну змінну, яку можна дозволити.
Джеремі

Відповіді:


66

Покрокове пояснення:

params Delegate?[] delegates - Це масив нульових Delegate

params Delegate?[]? delegates - Весь масив може бути зведений нанівець

Оскільки кожен параметр має тип, Delegate?і ви повертаєте індекс Delegate?[]?масиву, то має сенс, що тип повернення в Delegate?іншому випадку компілятор повертає помилку, як якщо б ви ретентувались, і intз методу, який повертає рядок.

Ви можете змінити, наприклад, свій код, щоб повернути такий Delegateтип:

public static Delegate Combine(params Delegate?[]? delegates)
{
    Delegate defaulDelegate = // someDelegate here
    if (delegates == null || delegates.Length == 0)
        return defaulDelegate;

    Delegate d = delegates[0] ?? defaulDelegate;
    for (int i = 1; i < delegates.Length; i++)
        d = Combine(d, delegates[i]);

    return d;
}

4
як щодо мого першого питання? Чому повернене значення використовує, ?хоча це вже посилання (клас) типу
snr -

2
Тому що ви повертаєтесь d, який є делегатом? тип. А також null або Delegate залежно від параметрів
Athanasios Kataras

2
@snr Значення повернення використовує ?точно з тієї ж причини, через яку в аргументі використовується значення аргументу ?. Якщо ви розумієте останнє, ви автоматично розумієте перше. Оскільки метод може повернути null , як параметр може приймати null . Тобто обидва вони можуть містити нуль .
GSerg

2
Я торкнувся його. Я просто відповів на це як другу частину прикладом. Since each parameter is of the type Delegate? and you return an index of the Delegate?[]? array, then it makes sense that the return type is Delegate?
Афанасіос Катарас

2
@snr: Для чого використовується значення повернення? хоча це вже посилальний (клас) тип (1) Це може бути звичка або рефакторинг залишок, якщо структури також використовуються в аналогічному коді (2) У C # 8 типи посилань можуть бути заборонені, щоб бути притаманними по суті (таким чином, вимагаючи явної нульовості ( 3) Foo?має чітке HasValueвластивість, тоді як Fooпотрібно == nullперевірити (4) Він повідомляє розробникам, які читають підпис методу, що нулі можливі, слід очікувати, і правильний результат. (5) Код, схоже, повинен бути написаний тим, хто дуже любить допустимість порожніх і бути явно про це.
Flater

25

Незмінні типи довідок є новими в C # 8.0, вони не існували раніше.

Це питання документації та того, як створюються попередження під час компіляції.

Виняток "об'єкт, не встановлений для екземпляра об'єкта", є винятком тихо. Але це виняток під час виконання, воно може частково виявитись під час компіляції.

Для регулювання Delegate dзавжди можна зателефонувати

 d.Invoke();

значить, ви можете це кодувати, в момент компіляції нічого не відбудеться. Це може спричинити винятки під час виконання.

У той час як для нового Delegate? pцього Кодексу

 p.Invoke();

створить попередження компілятора. CS8602: Dereference of a possibly null reference якщо ви не пишете:

 p?.Invoke();

що означає, дзвоніть лише якщо не нульовим.

Отже, ви документуєте змінну, може містити null чи ні. Він піднімає попередження раніше, і це дозволяє уникнути декількох тестів на нуль. Те саме, що у вас є для int та int ?. Ви точно знаєте, один не є нульовим - і ви знаєте, як перетворити одне на інше.


з застереженням, про яке ви точно не знаєте, що Delegateце недійсне. Ви просто робите вигляд, що знаєте напевно (що досить добре в більшості випадків).
Тім

@TimPohlmann Так само як int i = null неможливо, також строка s = null неможлива (в C # 8 при цій зміні розриву). Тож це трохи більше, ніж щось прикидатися. Для зворотної сумісності вона знижується до попередження. Якщо ви оновите попередження до помилки, ви точно знаєте, що це недійсне значення.
Хольгер

4
Минулого разу я перевіряв, що NRT не є 100-відсотковими. Існують певні крайні випадки, які компілятор не може виявити.
Тім

Так, але це те саме, що і попередження "змінна не ініціалізована" або "не всі кодові шляхи, що повертають значення". Це всі 100% функції компіляції, без виявлення під час виконання. На відміну від int ?, я думаю, що вони не додають додаткової пам’яті для зберігання додаткової інформації. Тож скажімо, це настільки ж надійно, як інтеліссенс. Досить добре.
Хольгер

1
Якщо у вас є, intвін ніколи не може бути нульовим. Якщо у вас є, Delegateце може бути нульовим (з різних причин, наприклад, рефлексія). Зазвичай можна з упевненістю припустити, що Delegate(у C # 8 із включеним NRT) не є нульовим, але ви ніколи не знаєте точно (де intми точно знаємо).
Тім

5

У C # 8 слід чітко позначити еталонні типи як нульові.

За замовчуванням ці типи не можуть містити нульові, схожі на типи значень. Хоча це не змінює спосіб роботи під кришкою, перевірка типу вимагатиме від вас це зробити вручну.

Даний код реконструюється для роботи з C # 8, але ця нова функція не має користі.

public static Delegate? Combine(params Delegate?[]? delegates)
{
    // ...[]? delegates - is not null-safe, so check for null and emptiness
    if (delegates == null || delegates.Length == 0)
        return null;

    // Delegate? d - is not null-safe too
    Delegate? d = delegates[0];
    for (int i = 1; i < delegates.Length; i++)
        d = Combine(d, delegates[i]);

    return d;
}

Ось приклад оновленого коду (не працює, просто ідея), що використовує цю функцію. Це врятувало нас від нульової перевірки та трохи спростило цей метод.

public static Delegate? Combine(params Delegate[] delegates)
{
    // `...[] delegates` - is null-safe, so just check if array is empty
    if (delegates.Length == 0) return null;

    // `d` - is null-safe too, since we know for sure `delegates` is both not null and not empty
    Delegate d = delegates[0];

    for (int i = 1; i < delegates.Length; i++)
        // then here is a problem if `Combine` returns nullable
        // probably, we can add some null-checks here OR mark `d` as nullable
        d = Combine(d, delegates[i]);

    return d;
}

2
those types are not able to contain null, Зверніть увагу , що він генерує компілятор попередження , а не про помилку. Код буде працювати нормально (хоча він може генерувати NullReferenceExceptions). Це робиться з урахуванням зворотної сумісності.
JAD
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.