请注意,这个问题是关于最新的 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
}
线路return Value.ToString();
给了我一个CS8603可能的空引用返回警告,我的问题实际上是为什么它在这里?
我正在使用where T : struct, IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable
匹配数字类型的通用约束,Value
实际上是值类型,而不是引用类型。 ToString()
也没有过载。对于任何值类型,默认 implementation对于 Int32
(例如)返回不可为空的 string
。 MSDN notes to inheritors还说
Your
ToString()
override should not returnEmpty
or anull
string.
编译器是否提示某些类型可以满足泛型约束并返回 null
来自ToString()
?
我可以通过使返回类型可为空来避免警告
public override string? ToString()
{
return Value.ToString();
}
或者使用空合并运算符
public override string ToString()
{
return Value.ToString() ?? "";
}
或者通过 null-forgiving 运算符
public override string ToString()
{
return Value.ToString()!;
}
但是这些选项看起来大多都是骗局,我正在寻找这种行为的解释,为什么会出现这种情况,是设计原因还是其他原因?除了上述方法之外,还有其他方法可以避免出现警告吗?
顺便说一句,此选项不起作用,警告仍然存在
[return: MaybeNull]
public override string ToString()
{
return Value.ToString();
}
我正在使用 .NET Core 3.1 和 VS 2019 16.4.2,但我认为这在这里并不重要。 预先感谢您的帮助!
最佳答案
object.ToString()
的签名是:
public virtual string? ToString()
即对象的ToString()
方法被定义为返回一个可能为空的字符串。
您的 Node.ToString()
重载严格了这一要求并 promise 返回非空字符串。这可以。 Int32
例如,这样做(正如您所指出的)。
但是,您的 Node.ToString()
方法返回 Value.ToString()
中的值。我们刚刚看到这个ToString
方法(即 object.ToString()
)可能返回 null
。因此,编译器警告您,您的 Node.ToString()
方法可能会无意中返回 null
,如果Value.ToString()
返回null
.
这解释了为什么您发现声明 Node.ToString()
如:
public override string? ToString()
抑制了警告:您现在声明您的 Node.ToString()
方法可能返回 null
,所以如果 Value.ToString()
则不是问题返回null
然后您返回该值。
这也解释了为什么写 return Value.ToString() ?? "";
抑制警告: if Value.ToString()
返回null
,该代码将确保 Node.ToString()
没有返回null
.
如何最好地解决这个问题?你决定。
您想要 promise 您的 Node.ToString()
方法永远不会返回null
?如果是这样,您需要弄清楚如果 Value.ToString()
该怎么办返回null
.
否则,最好遵循既定模式,并说您的 Node.ToString()
方法可能返回null
.
为什么 object.ToString()
返回string?
?请参阅this thread进行完整的讨论,但要点是有 ToString
do 返回 null
的野外方法,因为有些人不遵循“你永远不应该回来”的准则 null
或空字符串。
- 如果您引用的类型是在没有可为 null 的注释的情况下构建的,则
object.ToString()
返回string?
意味着除非您检查null
,否则您将收到警告。这可以保护您免受写得不好的ToString
的影响。方法。 - 如果您引用使用可空注释构建的类型,则:
- 作者遵循了指南,并声明了他们的
ToString
方法返回string
。在这种情况下,编译器假设您不会得到null
. - 作者明确没有遵循指南,并声明其
ToString
方法返回string?
。在这种情况下,您必须检查null
.
- 作者遵循了指南,并声明了他们的
请注意,当您创建 ToString
的重载时在 Visual Studio 中,生成的方法返回 string
(即使被重载的方法返回 string?
)。这会提示您遵循指南。
这里唯一的烦恼是当您处理泛型类型或已转换为 object
的类型时。在这种情况下,编译器不知道该对象是否是 ToString
方法是否遵循指南。因为object.ToString
返回string?
,编译器假设最坏的情况。如果您愿意,可以使用 null-forgiving 运算符 !
来覆盖此假设。 .
关于c# - 可空引用类型和 ToString() 重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59581046/