Programming w/ C# ~ record に対する override method

備忘録

原因不明の不具合に悩まされ、調べたら C# 言語仕様だったということがあったためメモ。

record の override method は class のそれと違う動作をする。

using System;

public class Class1 {
  public string PropC1 = "PropC1";
  public override string ToString() => "Class1";
}

public class Class2 : Class1 {
  public string PropC2 = "PropC2";
}

public record Record1 { 
  public string PropR1 = "PropR1";
  public /* sealed */ override string ToString() => "Record1";
}

public record Record2 : Record1 {
  public string PropR2 = "PropR2";
}

Console.WriteLine($"{new Class1()}");
Console.WriteLine($"{new Class2()}");
Console.WriteLine($"{new Record1()}");
Console.WriteLine($"{new Record2()}");

結果 ... class と record で出力が違う!

Class1                                       // Class1 .ToString() was called.
Class1                                       // Class1 .ToString() was called.
Record1                                      // Record1.ToString() was called.
Record2 { PropR1 = PropR1, PropR2 = PropR2 } // object .ToString() was called! Why?

record の (unsealed) override method を派生 record から呼んだ場合、直近の基底 record の method ではなく、最基底 record (つまり object) の method が適用される。

特に .ToString() はユーザ定義した基底 record の method が呼ばれなくて罠になる。解らなくて半日悩んだ。
record は拡張版 class ではなかったかと ...

このあたりの issue に関連しているか。
[Proposal]: Records with sealed base ToString override · Issue #4174 · dotnet/csharplang · GitHub