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.
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.
T
must be a reference type or a nullable type
public abstract class Feature<T> where T : class
{
// ...
}
As far as I know the ?.
operator is hardcoded to work with null
, that is, it works for reference types or nullable value types, but not normal value types. The problem is likely that the operator returns null
if the expression was null
instead of default(T)
.
You might be able to fix it by restricting T
to class
here.