Search code examples
c#recordtostringderived-classbase-class

C# record calls ToString in the base record instead of the one in the derived record


I have the following two records:

internal record Token
{
    private string content;

    public string Content
    {
        get => content;
        init => content = value ?? throw new ArgumentNullException(nameof(Content));
    }

    public int Position { get; init; }

    public Token(string content, int position)
    {
        Content = content ?? throw new ArgumentNullException(nameof(content));
        Position = position;
    }

    public override string ToString()
    {
        return Content;
    }

    public static implicit operator string(Token token)
    {
        return token.Content;
    }
}

internal record CommaToken : Token
{
    public CommaToken(int position) : base(",", position)
    {
    }
}

and when I do:

CommaToken comma = new(0);
Console.WriteLine(comma);

it just outputs this:

,

According to the docs, a record should have a compiler-synthesized ToString method unless another method with the same signature is defined. In my case, CommaToken doesn't have a ToString method defined, so it should use its own synthesized ToString instead of the one in Token. What have I done wrong?


Solution

  • It turns out that Console.WriteLine also accepts a string, so the compiler decided to use the public static implicit operator string(Token token) to cast CommaToken into a string, which caused the problem.
    I then learned that a conversion operator should be marked as explicit if the conversion will discard information of some type. In my case, casting a Token to a string is throwing away some information, so the conversion operator should be marked as explicit.