如何仅将C#8中的默认返回值标记为可为空的类?

Ray*_*Ray 3 c# generics non-nullable c#-8.0 nullable-reference-types

我当前正在尝试将新的C#8.0非空引用类型功能应用于现有代码,并且不知道如何在以下数据反序列化方法中解决CS8603警告:

T ReadOptional<T>() where T : IEntity, new()
{
    if (ReadBoolean())
    {
        T instance = new T();
        instance.Read(this); // IEntity method
        return instance;
    }
    else
    {
        // CS8603 Possible null reference return.
        return default;
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,如果前面的布尔值为false,则该方法可能返回null(classes)/ default(structs),否则它将返回一个T实例,该实例可以是任何实现的IEntity

但是,我不能将返回类型标记为T?,因为null如果T是struct,它实际上不会返回,如编译器错误CS8627正确抱怨的那样:

// CS8627: A nullable type parameter must be known to be a value type or non-nullable
// reference type. Consider adding a 'class', 'struct', or type constraint.
T? ReadOptional<T>() where T : IEntity, new()
Run Code Online (Sandbox Code Playgroud)
  • 我无法通过确保T具有class约束来解决此问题,因为我还希望struct实例能够与此方法一起使用(返回default)。
  • 我无法创建T具有struct约束的重载,因为重载不能仅因约束而不同。
  • 我可以创建不同名称的方法,但是这会破坏库接口,并导致过多的代码依赖于该接口。

是否有任何语法可以解决不可为空的警告,而又​​不会破坏default为结构返回实例的可能性?

Ray*_*Ray 5

在这里浏览类似的C#8.0问题,我在有关可为空的引用类型的知识方面填补了空白:有一个可为空的操作符!,可以在这里为我修复警告:

T ReadOptional<T>() where T : IEntity, new()
{
    if (ReadBoolean())
    {
        T instance = new T();
        instance.Read(this); // IEntity method
        return instance;
    }
    else
    {
        return default!; // <-- note the exclamation mark
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 等等,这似乎不正确。类型T被标记为不可空的,因此无论什么类型,调用ReadOptional必须保证它不为null,因此这欺骗了编译器,但更重要的是,这可能会导致细微的错误。只是这么说,所以每个人都应该意识到这一点。 (2认同)