在扩展方法中使用 Null 条件运算符时出错

Error using Null-conditional operators in extension method

我很困惑这里出了什么问题:

public static T? GetValue<T>(this JObject o, string propertyName)  
{
  JToken? jtok = o.GetValue(propertyName); 
  return jtok?.ToObject<T>();
}

我得到:

error CS0023: Operator '?' cannot be applied to operand of type 'T'

(在?.)

这里有什么问题吗? GetValue returns JToken? 不是 T

编译器抛出错误,因为你试图将你已经限制为 notnull 的东西 return 设为 null,这意味着你告诉编译器 T 永远不会为 null,同时你还期望 T 可能将来在某个时候变为空。 这是没有编译器错误和相同逻辑的替代解决方案

public static T GetValue<T>(this JObject o, string propertyName) where T : notnull
{
    if (o.TryGetValue(propertyName, out JToken jtok))
        return jtok.ToObject<T>();
    else return default;
}

或者这里是一样的,语法更优雅

public static T GetValue<T>(this JObject o, string propertyName) where T : notnull
    => o.TryGetValue(propertyName, out JToken jtok) ? jtok.ToObject<T>() : default;

如果您不明白代码,请在评论中提问

编辑第一条评论后:

现在(删除 notnull 约束后)你的代码告诉编译器 T 可以是任何东西(值(不可空)或引用(可空)类型)所以当你检查 jtok?. 你告诉编译器在某些时候它应该期望空值,如果 T 是例如 int 将会出错,因为你不能直接将 null 分配给 int

考虑您的代码的这个用例 int i = sampleObj.GetValue<int>("EXAMPLE");。在这种情况下,如果“EXAMPLE”属性 不存在,您将强制编译器将 null 分配给 int,但编译器很聪明,它会抛出该错误以保护您免受该错误的影响

因为您没有指定 T 是 class(引用类型)或结构(不可空值类型),所以 ?. 运算符无法知道要提升哪种类型.

您可以将其修改为where T : class来解决问题(在您的情况下我认为T将是class。)

更详细的解释,包括?.运算符生成的确切代码是什么,您可以查看现有问题: