C# 9.0 记录 - ToString 未继承

C# 9.0 records - ToString not inherited

考虑:

// the ratioale for Wrapper is that it has a Json serializer that  
// serialize through Field (not included in this example)
record Wrapper<T> where T : notnull {
  protected Wrapper(T field) => Field = field; 
  protected Wrapper(Wrapper<T> wrapper) => Field = wrapper.Field;
  protected readonly T Field;
  public override string ToString() => Field.ToString() ?? "";
}

record MyRec : Wrapper<string> {
    public MyRec(string s) : base(s) {}
}

public static class Program {
  public static void Main(string[] args) {
      var r = new MyRec("hello");
      Console.WriteLine(r.ToString());
  }
}

sharplab

似乎基 ToString 不是继承的,编译器仍然自动生成派生的 Tostring

这是为什么?有什么好的解决办法吗?

record 声明取代继承的 ToString()What's New 描述中对此进行了解释:

The compiler synthesizes two methods that support printed output: a ToString() override, and PrintMembers.

基本 class(也是 record)具有 ToString 覆盖的事实未被考虑。从技术上讲,所有 类型从 object 继承 ToString(),因此 record 类型的代码生成器不会查看继承覆盖的基类型,否则compiler-generated ToString 永远不会 创建。

(您可能会争辩说应该保留继承的 record 类型中的 ToString,但这不是该功能的设计方式)。

但是如果记录类型有一个被覆盖的 ToString(),那么编译器不会生成一个:

If a record type has a method that matches the signature of any synthesized method, the compiler doesn't synthesize that method.

您可以定义一个看似多余的覆盖:

public override string ToString() => base.ToString();

由于 record 声明,这应该可以防止编译器 auto-generating ToString 覆盖。

有评论为我解决了这个问题。 Sean 说,如果您将 sealed 添加到方法中,它会阻止编译器合成 .ToString() 方法,请参见下文

public sealed override string ToString() => Value;