考虑这个类:
public class Number
{
[System.Obsolete()] public string ToExactString() => "";
[System.Obsolete()] public override string ToString() => "";
}
现在,考虑以下代码:
Number number = new();
string s1 = number.ToExactString();
string s2 = number.ToString();
现在,观察一下发生了什么:
ToExactString()
Visual Studio 会用删除线来呈现 的调用,并且编译器会生成警告 CS0612:“'member' 已过时”。ToString()
Visual Studio也会用删除线来呈现调用,但编译器不会生成任何警告。
因此:
我那双衰老的眼睛是否注意到了 调用上的删除线并不重要ToExactString()
,因为编译器会在构建过程中让我知道,而且我甚至可以启用“将所有警告视为错误”以确保万无一失,这样我就永远不会意外运行调用过时方法的代码。
然而,如果我没有注意到那句调用中的删除线ToString()
,我永远不会知道。
请注意以下几点:
这两种方法的区别在于ToExactString()
不是覆盖,而ToString()
是对非过时方法的覆盖,但在这种情况下 这应该是完全不相关且完全无关紧要的,因为我持有的是对 的引用Number
,而不是对 的引用object
。
这并不重要,但要明确的是,在我的所有 C# 项目中,我都禁用了 CS0809:“过时的成员覆盖非过时的成员” ,因为这个警告完全没有意义,因为在某些情况下,用过时的成员覆盖非过时的成员是完全可以的,甚至是非常可取的,就像这里的情况一样ToString()
。这里的重点是我想创建一个过时的覆盖,没有人应该直接调用它,即使它可以由持有对基类的引用的代码合法地调用。
Visual Studio 将所有调用都呈现为带有删除线的形式,这表明 Visual Studio 完全理解在每种情况下调用了哪种方法,而 Roslyn 则假装不理解在的情况下调用了哪种方法ToString()
,就好像它是一个覆盖有什么关系一样。
如果[System.Obsolete()]
被替换,[System.Obsolete("message")]
那么调用 CS0618 更改时会出现警告ToExactString()
:“成员”已过时:“消息”,但其他一切都没有任何变化。
问题:
- 这是 C# 编译器的一个错误吗?
- 是否有已知的修复方法或解决方法?