Attributes for record auto-property in C#9

O record ako novom spôsobe pre jednoduché a elegantné vytváranie immutable objektov sa popísalo veľa. Napríklad tu.

Jednou zo zaujímavých vlastností je možnosť využiť syntaxt nazývanú positional records.
V tomto prípade môžeme definovať jednotlivé property priamo v konštruktore.

public record Person(string FirstName, string LastName);

Problém môže nastať, pokiaľ daným property chceme nastaviť atribút. Napríklad [JsonProperty].
Prvoplánovo to môžeme skúsiť nasledovne.

public record Person([JsonProperty("name")]string FirstName, string LastName);

Keby sme sa však pozreli na skutočne vygenerovaný kód, tak uvidíme niečo nasledovné:

// Simplied code 
public class Person : IEquatable<Person>
{
    public string FirstName
    {
        get;
        init;
    }

    public string LastName
    {
        get;
        init;
    }

    public Person([JsonProperty("name")] string FirstName, string LastName)
    {
        this.FirstName = FirstName;
        this.LastName = LastName;
    }
}

A to nie je to čo sme chceli. My sme chceli nastaviť ten atribút pre property, nie pre parameter konštruktora.
Samozrejme môžeme použiť tradičnú syntaxt s deklaráciou properties.

public record Person
{
    [JsonProperty("name")]
    public string FirstName { get; init; } 

    public string LastName { get; init; }

    public Person(string firstName, string lastName) 
      => (FirstName, LastName) = (firstName, lastName);
}

Ale čo keď naozaj chceme použiť positional records?

Riešením je použitie property:.

public record Person([property:JsonProperty("name")]string FirstName, string LastName);

Attributes can be applied to the synthesized auto-property and its backing field by using property: or field: targets for attributes syntactically applied to the corresponding record parameter. Viď špecifikácia.

Pokiaľ si to pozrieme napríklad cez ILSpy tak uvidíme niečo nasledovné.

// Simplied code 
public class Person : IEquatable<Person>
{
    [JsonProperty("name")]
    public string FirstName
    {
        get;
        init;
    }

    public string LastName
    {
        get;
        init;
    }

    public Person(string FirstName, string LastName)
    {
        this.FirstName = FirstName;
        this.LastName = LastName;
    }
}

A to je to čo sme chceli dosiahnúť. (Teda aspoň ja 😉)