Dwukrotne definiowanie właściwości w rekordzie
W C # 9 można zdefiniować właściwość o tej samej nazwie w rekordzie zarówno w konstruktorze głównym, jak iw treści:
record Cat(int PawCount)
{
public int PawCount { get; init; }
}
Ten kod kompiluje się bez błędów.
Podczas inicjowania wystąpienia takiego rekordu wartość przekazana konstruktorowi jest całkowicie ignorowana:
Console.WriteLine(new Cat(4));
Console.WriteLine(new Cat(4) { PawCount = 1 });
wydruki
Cat { PawCount = 0 }
Cat { PawCount = 1 }
Czy to zachowanie jest prawidłowe, czy jest to błąd? Jeśli jest poprawna, w jakich przypadkach jest przydatna?
Spodziewałem się, że kompilator albo odrzuci ten kod z błędem typu „Typ Cat
już zawiera definicję dla PawCount
”, albo uzna właściwość w konstruktorze i w treści za taką samą, wykonując inicjalizację z konstruktora. Ten ostatni wariant może być przydatny do dostarczania właściwości z niestandardowym narzędziem pobierającym i / lub inicjalizatorem bez konieczności przepisywania wszystkich właściwości rekordu pozycyjnego w jego treści.
Faktyczne zachowanie nie ma dla mnie sensu.
Odpowiedzi
Prawidłowy sposób to:
record Cat(int PawCount)
{
public int PawCount { get; init; } = PawCount;
}
Jest to przydatne, ponieważ umożliwia np. Walidację
record Cat(int PawCount)
{
private int _pawCount;
public int PawCount {
get => _pawCount;
init => _pawCount = value < 0 ? throw new ArgumentException() : value;
} = PawCount;
}
Specyfikacja tego jest tutaj: https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/records.md#members-of-a-record-type
Składowe są syntetyzowane, chyba że w treści rekordu zadeklarowano element członkowski z „zgodnym” podpisem lub dziedziczony jest dostępny konkretny niewirtualny element członkowski z „pasującym” podpisem. Dwóch członków jest uważanych za pasujących, jeśli mają ten sam podpis lub zostaliby uznani za „ukrywających się” w scenariuszu dziedziczenia.
Ponieważ więc istnieje już właściwość o takiej samej nazwie, jak parametr, kompilator nie zsyntetyzuje PawCount
właściwości, więc po prostu dyskretnie ignoruje parametr, chyba że sam go użyjesz.