C# 9.0 记录 - ToString 未继承

kof*_*fus 3 c# c#-9.0

考虑:

// 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());
  }
}
Run Code Online (Sandbox Code Playgroud)

夏普实验室

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

这是为什么 ?有什么好办法吗?

小智 23

有一条评论为我解决了这个问题。Sean 说,如果您添加sealed到该方法中,它会阻止编译器合成该ToString方法,如下所示:

public sealed override string ToString() => Value;
Run Code Online (Sandbox Code Playgroud)

ToString请注意,C# 10 中引入了密封覆盖的功能


D S*_*ley 8

record声明取代了继承的ToString(). 这在新增功能描述中进行了解释:

编译器综合了两种支持打印输出的方法:ToString() 覆盖和 PrintMembers。

不考虑基类(也是 a record)具有ToString覆盖的事实。从技术上讲所有类型继承ToString()object,所以代码生成器record的类型并不在基本类型寻找一个继承覆盖,否则编译器生成的ToString永远不会被创建。

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

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

如果记录类型具有与任何合成方法的签名匹配的方法,则编译器不会合成该方法。

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

public override string ToString() => base.ToString();
Run Code Online (Sandbox Code Playgroud)

这应该可以防止编译器ToString由于record声明而自动生成覆盖。

  • 您可能想更新您的答案。现在可以在 C# 10 中密封 .ToString() 重写,以便编译器不再合成 .ToString() 方法来继承记录。 (5认同)