Pav*_*ski 4 c# .net-core c#-8.0 nullable-reference-types
请注意,这个问题是关于最新的 C# 8 nullable-references,我已经csproj通过以下<Nullable>enable</Nullable>声明在文件中启用了它。
考虑下面的简单代码
class SortedList<T> where T : struct, IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable
{
private Node? _node;
private readonly IComparer<T> _comparer = Comparer<T>.Default;
class Node
{
public Node(T value)
{
Value = value;
}
public T Value { get; }
public Node? Next { get; set; }
public override string ToString()
{
return Value.ToString();
}
}
//rest of code, that isn't important
}
Run Code Online (Sandbox Code Playgroud)
该行return Value.ToString();给了我一个CS8603 可能的空引用返回警告,我的问题实际上为什么在这里?
我使用where T : struct, IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable通用约束来匹配数字类型,Value实际上是值类型,而不是引用类型。也没有过载ToString()到任何类型的值,则默认的实现为Int32(例如)返回不可为空string。MSDN给继承者的注释也说
您的
ToString()覆盖不应返回Empty或null字符串。
编译器是否抱怨某种类型,它可以满足泛型约束并null从返回ToString()?
我可以通过使返回类型可以为空来避免警告
public override string? ToString()
{
return Value.ToString();
}
Run Code Online (Sandbox Code Playgroud)
或使用空合并运算符
public override string ToString()
{
return Value.ToString() ?? "";
}
Run Code Online (Sandbox Code Playgroud)
或通过空值原谅运算符
public override string ToString()
{
return Value.ToString()!;
}
Run Code Online (Sandbox Code Playgroud)
但这些选项看起来大多是一种技巧,我正在寻找这种行为的解释,为什么会出现,设计或任何其他原因发生?除了上面的那些,还有什么方法可以避免这个警告?
顺便说一句,这个选项不起作用,警告仍然存在
[return: MaybeNull]
public override string ToString()
{
return Value.ToString();
}
Run Code Online (Sandbox Code Playgroud)
我正在使用 .NET Core 3.1 和 VS 2019 16.4.2,但我认为这在这里并不重要。预先感谢您的帮助!
can*_*on7 14
public virtual string? ToString()
Run Code Online (Sandbox Code Playgroud)
也就是说,对象的ToString()方法被定义为返回一个可能为空的字符串。
你的重载Node.ToString()收紧了这个要求并承诺返回一个非空字符串。这可以。Int32例如,这样做(如您所言)。
但是,您的Node.ToString()方法从 返回值Value.ToString()。我们刚刚看到这个ToString方法(即object.ToString())可能会返回null。因此,编译器警告您,如果返回,您的Node.ToString()方法可能会无意中返回。nullValue.ToString()null
这解释了为什么您发现声明Node.ToString()为:
public override string? ToString()
Run Code Online (Sandbox Code Playgroud)
抑制警告:您现在声明您的Node.ToString()方法可能会返回null,因此如果Value.ToString()返回null并返回此值,这不是问题。
它还解释了为什么编写return Value.ToString() ?? "";抑制警告:如果Value.ToString()返回null,该代码将确保Node.ToString()没有返回null。
如何最好地解决这个问题?你决定。
你想保证你的Node.ToString()方法永远不会返回null吗?如果是这样,您需要弄清楚如果Value.ToString()返回该怎么办null。
否则,最好遵循既定的模式,并说明您的Node.ToString()方法可能会返回null.
为什么不object.ToString()回string??有关完整讨论,请参阅此线程,但要点是有些ToString方法确实会return null,因为有些人不遵循永远不应该 returnnull或空字符串的准则。
object.ToString()返回的事实string?意味着您将收到警告,除非您检查null. 这可以保护您免受编写不当的ToString方法的影响。ToString方法为返回string。在这种情况下,编译器假定您不会得到null.ToString方法为返回string?。在这种情况下,您被迫检查null.请注意,当您ToString在 Visual Studio 中创建 的重载时,生成的方法将返回string(即使重载的方法返回string?)。这会提示您遵循这些准则。
这里唯一的烦恼是当您处理泛型类型或已强制转换为object. 在这种情况下,编译器不知道对象的ToString方法是否遵循准则。因为object.ToStringreturn string?,编译器会假设最坏的情况。如果您希望使用 null-forgiving operator ,您可以覆盖此假设!。