Operator '?' cannot be applied to operand of type 'T'

Sinatr picture Sinatr · Sep 15, 2015 · Viewed 7.3k times · Source

Trying to make Feature generic and then suddenly compiler said

Operator '?' cannot be applied to operand of type 'T'

Here is the code

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; }
}

It is possible to use this code instead

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

But I am wondering how to fix that nice C# 6.0 one-liner.

Answer

Patrick Hofman picture Patrick Hofman · Sep 15, 2015

Since not everything can be null, you have to narrow down T to be something nullable (aka an object). Structs can't be null, and neither can enums.

Adding a where on class does fix the issue:

public abstract class Feature<T> where T : class

So why doesn't it just work?

Invoke() yields T. If GetValue is null, the ? operator sets the return value of type T to null, which it can't. If T is int for example, it can't make it nullable (int?) since the actual type required (T = int) isn't.

If you change T to be int in your code, you will see the problem very clearly. The end result of what you ask is this:

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

This is not something the null-propagation operator will do for you. If you revert to the use of default(T) it does know exactly what to do and you avoid the 'problematic' null-propagation.