-
(Don't know if that's the compiler or spec issue.) The current spec proposal about the record copy constructor says the following (emphasis is mine):
From that, I would expect the following code (sharplab) to generate the public record Number
{
public int N { get; set; }
protected Number(Number original) => N = original.N;
} It doesn't. Also, if I remove the user-defined copy constructor, the auto-generated one doesn't contain the protected Number(Number original)
{
<N>k__BackingField = original.<N>k__BackingField;
} With record inheritance: public record Empty;
public record Number : Empty
{
public int N { get; set; }
protected Number(Number original) => N = original.N;
} the following error is generated: error CS8868: A copy constructor in a record must call a copy constructor of the base, or a parameterless object constructor if the record inherits from object. So, when is it really necessary to call a parameter-less object constructor? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
I think the spec is meant to allow calling .method family hidebysig specialname rtspecialname
instance void .ctor (
class Number original
) cil managed
{
// Method begins at RVA 0x20ab
// Code size 19 (0x13)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [System.Private.CoreLib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: ldarg.1
IL_0008: callvirt instance int32 Number::get_N()
IL_000d: call instance void Number::set_N(int32)
IL_0012: ret
} // end of method Number::.ctor For the auto-generated one, it's: .method family hidebysig specialname rtspecialname
instance void .ctor (
class Number original
) cil managed
{
// Method begins at RVA 0x21d0
// Code size 19 (0x13)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [System.Private.CoreLib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: ldarg.1
IL_0008: ldfld int32 Number::'<N>k__BackingField'
IL_000d: stfld int32 Number::'<N>k__BackingField'
IL_0012: ret
} // end of method Number::.ctor Notice that in both cases, the I think that part of the spec is meant to forbid code like the following: public record Number
{
public int N { get; set; }
protected Number(Number original) : this() => N = original.N;
public Number() {}
} Which does produce an error message that mirrors the spec:
|
Beta Was this translation helpful? Give feedback.
-
Thank you @svick. So, the parameter-less object constructor call is automatically added by the compiler to follow the spec. That leaves the error message a bit misleading to a developer, because for your example of the erroneous code the following message would be clearer:
The current error message suggests the following solution: public record Number
{
public int N { get; set; }
protected Number(Number original) : base() => N = original.N;
public Number() {}
} which is fine, but not necessary. |
Beta Was this translation helpful? Give feedback.
I think the spec is meant to allow calling
base()
in this case implicitly, which is what happens both with your hand-written and auto-generated copy constructors. One way to see that is to look at the generated IL. For the hand-written constructor, it's: