What is the output of that code snippet?
Console.Write(new Derived("Test"));
public abstract record Base(string Key)
{
public override string ToString() => Key;
}
public sealed record DerivedRecord(string Key) : Base(Key);
Probably "Test"?
Lowered Code
If we have a look at the following lowered code:
[NullableContext(1)]
[Nullable(0)]
public abstract class Base : IEquatable<Base>
{
[CompilerGenerated]
private readonly string <Key>k__BackingField;
[CompilerGenerated]
protected virtual Type EqualityContract
{
[CompilerGenerated]
get
{
return typeof(Base);
}
}
public string Key
{
[CompilerGenerated]
get
{
return <Key>k__BackingField;
}
[CompilerGenerated]
init
{
<Key>k__BackingField = value;
}
}
protected Base(string Key)
{
<Key>k__BackingField = Key;
base..ctor();
}
public sealed override string ToString()
{
return Key;
}
// ....
}
[NullableContext(1)]
[Nullable(0)]
public sealed class DerivedRecord : Base, IEquatable<DerivedRecord>
{
[CompilerGenerated]
protected override Type EqualityContract
{
[CompilerGenerated]
get
{
return typeof(DerivedRecord);
}
}
public DerivedRecord(string Key)
: base(Key)
{
}
[CompilerGenerated]
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("DerivedRecord");
stringBuilder.Append(" { ");
if (PrintMembers(stringBuilder))
{
stringBuilder.Append(' ');
}
stringBuilder.Append('}');
return stringBuilder.ToString();
}
[CompilerGenerated]
protected override bool PrintMembers(StringBuilder builder)
{
return base.PrintMembers(builder);
}
/...
I left many parts out for simplicity
So ToString is "reimplemented" in the derived class, where we construct everything of the derived class and call PrintMembers of the base class. So if we call that snippet we get:
DerivedRecord { Key = Test }
So not just "Test". To fix that, C# 10 introduced that we are able to add sealed to methods that are offered by the record construct:
public abstract record Base(string Key)
{
- public override string ToString() => Key;
+ public sealed override string ToString() => Key;
}
public sealed record DerivedRecord(string Key) : Base(Key);
And now we "just" have "Test" as output!