Подтвердить что ты не робот

Оператор '?' не может быть применено к операнду типа 'T'

Попытка сделать Feature общий, а затем компилятор вдруг сказал

Оператор '?' не может применяться к операнду типа "T"

Вот код

public abstract class Feature<T>
{
    public T Value
    {
        get { return GetValue?.Invoke(); } // here is error
        set { SetValue?.Invoke(value); }
    }

    public Func<T> GetValue { get; set; }
    public Action<T> SetValue { get; set; }
}

Вместо этого можно использовать этот код

get
{
    if (GetValue != null)
        return GetValue();
    return default(T);
}

Но мне интересно, как исправить этот приятный однострочный С# 6.0.

4b9b3361

Ответ 1

Так как не все может быть null, вы должны сузить T на то, чтобы быть чем-то нулевым (aka a object). Структуры не могут быть нулевыми, а также не могут перечисления.

Добавление where в class устраняет проблему:

public abstract class Feature<T> where T : class

Так почему же он не работает?

Invoke() дает T. Если GetValue - null, оператор ? устанавливает возвращаемое значение типа T в null, чего не может. Если T является int, например, он не может сделать его нулевым (int?), поскольку требуемый фактический тип (T= int) не является.

Если вы измените T на int в своем коде, вы увидите проблему очень четко. Конечный результат вашего запроса:

get
{
    int? x = GetValue?.Invoke();
    return x.GetValueOrDefault(0);
}

Это не то, что оператор нулевого распространения сделает для вас. Если вы вернетесь к использованию default(T), он точно знает, что делать, и вы избегаете "проблемного" распространения нуля.

Ответ 2

T должен быть ссылочным типом или типом с нулевым значением

public abstract class Feature<T> where T : class
{
    // ...
}

Ответ 3

Насколько я знаю, оператор ?. жестко запрограммирован для работы с null, то есть он работает для типов ссылок или типов с нулевым значением, но не для нормальных типов значений. Вероятно, проблема заключается в том, что оператор возвращает null, если выражение null вместо default(T).

Возможно, вы сможете исправить это, ограничив T на class здесь.