In C# 9, one can define a property with the same name in a record both in its primary constructor and in its body:
record Cat(int PawCount)
{
public int PawCount { get; init; }
}
This code compiles without errors.
When initializing an instance of such a record, the value provided to the constructor is completely ignored:
Console.WriteLine(new Cat(4));
Console.WriteLine(new Cat(4) { PawCount = 1 });
prints
Cat { PawCount = 0 }
Cat { PawCount = 1 }
Is this behavior correct or is it a bug? If it’s correct, what are the cases in which it is useful?
I expected the compiler to either reject this code with an error like ‘The type Cat
already contains a definition for PawCount
’ or consider the property in the constructor and in the body the same, performing its initialization from the constructor.
The latter variant could be useful to provide the property with a custom getter and/or initializer without having to rewrite all the properties of the positional record in its body.
The actual behavior makes no sense to me.
You define a record by declaring a type with the record keyword, instead of the class or struct keyword. Optionally, you can declare a record class to clarify that it's a reference type. A record is a reference type and follows value-based equality semantics.
A record struct declares a value type. Positional properties are immutable in a record class and a readonly record struct . They're mutable in a record struct .
This is the stand out reason why you would want to use C# Records they are ideal in situations where you are going to need to compare objects and maybe you want to ensure the property values of an object cannot be changed during the execution of other processes.
A record type in C# 9 is a lightweight, immutable data type (or a lightweight class) that has read-only properties only. Because a record type is immutable, it is thread-safe and cannot mutate or change after it has been created. You can initialize a record type only inside a constructor.
Record types are reference types, so a record instance contains only a reference to the data. You can use positional parameters to declare properties of a record and to initialize the property values when you create an instance: When you use the positional syntax for property definition, the compiler creates:
Beginning with C# 9, you use the recordkeyword to define a reference typethat provides built-in functionality for encapsulating data. You can create record types with immutable properties by using positional parameters or standard property syntax: public record Person(string FirstName, string LastName);
A record can inherit from another record. However, a record can't inherit from a class, and a class can't inherit from a record. Positional parameters in derived record types
While records can be mutable, they're primarily intended for supporting immutable data models. The record type offers the following features: Concise syntax for creating a reference type with immutable properties Built-in behavior useful for a data-centric reference type:
The correct way to do this is:
record Cat(int PawCount)
{
public int PawCount { get; init; } = PawCount;
}
This is useful as it allows you to do e.g. validation
record Cat(int PawCount)
{
private int _pawCount;
public int PawCount {
get => _pawCount;
init => _pawCount = value < 0 ? throw new ArgumentException() : value;
} = PawCount;
}
The spec for this is here: https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/records.md#members-of-a-record-type
Members are synthesized unless a member with a "matching" signature is declared in the record body or an accessible concrete non-virtual member with a "matching" signature is inherited. Two members are considered matching if they have the same signature or would be considered "hiding" in an inheritance scenario.
So since a property with the same name as the parameter already exists, the compiler wont synthesize a PawCount
property, and so just silently ignores the parameter unless you use it yourself explicitly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With