The C# 9 records feature specification includes the following:
A record type contains two copying members:
A constructor taking a single argument of the record type. It is referred to as a "copy constructor". A synthesized public parameterless instance "clone" method with a compiler-reserved name
But I cannot seem to call either of these two copying members:
public record R(int A);
// ...
var r2 = new R(r); // ERROR: inaccessible due to protection level
var r3 = r.Clone(); // ERROR: R does not contain a definition for Clone
From this, I understand that the constructor is protected and thus can't be accessed outside the record's inheritance hierarchy. And so we're left with code like this:
var r4 = r with { };
But what about cloning? The clone method is public according to the specification above. But what is its name? Or is it an effectively random string so that it should not be called outside the record's inheritance hierarchy? If so, what is the correct way to deep copy records? It seems from the specification that one is able to create one's own clone method. Is this so, and what would be an example of how it should work?
This is called “Shallow Copy”. To get the same behavior for a Reference Type as well as a Value Type we use the Clone() method that belongs to the System. ICloneable interface. This is called a “Deep Copy”. We will see both behaviors in depth one by one.
But what about cloning?
var r4 = r with { };
performs a shallow clone on r.
The clone method is public according to the specification above. But what is its name?
The C# compiler has a fairly common trick where it gives generated members names which are illegal in C#, but legal in IL, so that they can't be called except from the compiler, even if they're public. In this case the name of the Clone
method is <Clone>$
.
If so, what is the correct way to deep copy records?
Deep copying you're out of luck. However since records should ideally be immutable, there should be no difference in practice between a shallow copy, a deep copy, and the original instance.
It seems from the specification that one is able to create one's own clone method. Is this so, and what would be an example of how it should work?
Unfortunately this didn't make the cut for C# 9, but there's a strong chance it'll be in C# 10.
To perform deep clone, you add your own copy constructor to a record:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public record EmployeeRecord(int UniqueId, Person Employee)
{
// Custom copy constructor (Should be protected or private)
protected EmployeeRecord(EmployeeRecord other)
{
UniqueId = other.UniqueId;
// Do deep copy stuff
Employee = new Person
{
FirstName = Employee.FirstName,
LastName = Employee.LastName
};
}
}
The compiler will not generate its own in this case. Then you use the "with" keyword:
var emp1 = new EmployeeRecord(100,
new Person { FirstName = "John", LastName = "Doe" });
var emp2 = emp1 with { };
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