web-dev-qa-db-ja.com

演算子 '?'タイプ「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);
}

しかし、私はその素敵なC#6.0ワンライナーを修正する方法を考えています。

26
Sinatr

すべてがnullになるわけではないので、Tをnull許容値(別名object)に絞り込む必要があります。構造体をnullにすることはできず、列挙型にすることもできません。

whereclassを追加すると、問題が修正されます。

_public abstract class Feature<T> where T : class
_

では、なぜそれがうまくいかないのですか?

Invoke()Tを生成します。 GetValuenullの場合、_?_演算子はタイプTの戻り値をnullに設定しますがこれはできません。たとえば、Tintの場合、実際の型が必要なため(T = int)、null許容(_int?_)にすることはできません。 )ではありません。

コードでTintに変更すると、問題が非常に明確にわかります。あなたが尋ねることの最終結果はこれです:

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

これは、null伝搬演算子が行うことではありません。 default(T)の使用に戻ると、何をすべきかが正確にわかり、「問題のある」null伝播を回避できます。

32
Patrick Hofman

Tは、参照型またはnull許容型である必要があります

public abstract class Feature<T> where T : class
{
    // ...
}
8
György Kőszeg

私の知る限り、_?._演算子はnullで機能するようにハードコードされています。つまり、参照型またはnull許容値型では機能しますが、normal値型では機能しません。この問題は、式がdefault(T)ではなくnullの場合、演算子がnullを返す可能性があります。

ここでTclassに制限することで修正できる可能性があります。

4
Joey