【问题标题】:Operator '?' cannot be applied to operand of type 'T'操作员 '?'不能应用于“T”类型的操作数
【发布时间】:2015-12-11 09:12:21
【问题描述】:

试图使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 单线。

【问题讨论】:

  • 这真的很有趣。我认为这可能是一个错误。正如您的第二个代码块所示,所有建议使用where T : class 的答案都缺少您正在检查Func&lt;T&gt; 是否为空而不是T 的事实。如果这样可行,那么GetValue?.Invoke() 语法也应该可以使用。你应该可以写:return GetValue?.Invoke() ?? default(T)
  • @kjbartel:我认为这是由于?. 返回null,如果表达式是null,而不是default(T)
  • Func 可以为空。
  • 我认为,问题是编译器无法确定GetValue?.Invoke() 的结果类型。如果TclassNullable&lt;&gt;,则结果类型应为T,但如果Tstruct,则结果类型应为T?
  • @kjbartel List?.Count 的结果类型是 int?。在编译时就知道,该类型应该提升为可为空的。 GetValue?.Invoke() 的结果类型为 TT?。在编译时不知道,应该将类型提升为可为空的,还是已经可以为空。

标签: c# generics delegates c#-6.0 null-propagation-operator


【解决方案1】:

由于并非所有内容都可以是 null,因此您必须缩小 T 的范围,使其可以为空(又名 object)。结构不能为空,枚举也不能。

class 上添加where 确实可以解决问题:

public abstract class Feature<T> where T : class

那么为什么它不能正常工作呢?

Invoke() 产生T。如果GetValuenull,则? 运算符将T 类型的返回值设置为null,它不能。例如,如果Tint,它不能使其为空(int?),因为所需的实际类型(T = int)不是。

如果您在代码中将T 更改为int,您将非常清楚地看到问题所在。你问的最终结果是这样的:

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

这不是空传播运算符将为您做的事情。如果您恢复使用default(T),它确实知道该做什么,并且您避免了“有问题的”空传播。

【讨论】:

  • 我只能接受 C# 编译器不允许这样做,并且您需要您的选项 #2 才能使其工作。不是所有的东西都必须是一个班轮,对吧?
  • 实际错误是Cannot lift conditional access expression type 'T' to nullable type.? 运算符将 child 的返回类型包装到 Nullable&lt;&gt; 中。编译器可以处理Nullable&lt;void&gt;,但不能处理Nullable&lt;T&gt;。这就是为什么Action&lt;T&gt;.Invoke 没有错误的原因。
  • @Sinatr 你可以用另一种方式做到这一点,参考 T 结构:public abstract class Feature&lt;T&gt; where T : struct。然后将所有T 类型标记为空。 public Func&lt;T?&gt;,public Action&lt;T?&gt;,public T? Value.但是这样你只能使用值类型。
  • @kjbartel 这个答案是正确的。 由于并非所有内容都可以为空, 这是真的,这就是为什么nullable&lt;T&gt; 无效。因为只有不可为空的东西才能被标记为nullable
  • @kjbartel Invoke() 产生 T。如果GetValuenull,则? 运算符将T 类型的返回值设置为null,它不能。
【解决方案2】:

T 必须是引用类型或可为空的类型

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

【讨论】:

    【解决方案3】:

    据我所知,?. 运算符被硬编码为与null 一起使用,也就是说,它适用于引用类型或可为空的值类型,但不适用于 普通 值类型。如果表达式是null 而不是default(T),则该问题很可能是运算符返回null

    您可以通过在此处将T 限制为class 来解决此问题。

    【讨论】:

    • @PanagiotisKanavos: Nullable&lt;T&gt; 被编译器视为可为空的,就像它应该的那样,但 it's a value type
    • 应该先检查参考来源!
    猜你喜欢
    • 2013-06-09
    • 1970-01-01
    • 2013-11-06
    • 2016-05-15
    • 1970-01-01
    • 1970-01-01
    • 2016-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多