I have a Wheel
class with two init-only properties Spokes
and DiskBrake
:
public class Wheel
{
internal Wheel() { }
public int Spokes { get; init; }
public bool DiskBrake { get; init; }
}
It is critical for the functionality of this class that these properties are immutable after the instantiation of a Wheel
object. So it is highly desirable for the properties to be init-only, and backed by a readonly
fields.
Now I have a Bicycle
class that contains two instances of the Wheel
class:
public class Bicycle
{
private readonly Wheel _frontWheel = new();
private readonly Wheel _rearWheel = new();
public int FrontWheelSpokes
{
get => _frontWheel.Spokes;
init => _frontWheel.Spokes = value;
}
public int RearWheelSpokes
{
get => _rearWheel.Spokes;
init => _rearWheel.Spokes = value;
}
public bool FrontWheelDiskBrake
{
get => _frontWheel.DiskBrake;
init => _frontWheel.DiskBrake = value;
}
public bool RearWheelDiskBrake
{
get => _rearWheel.DiskBrake;
init => _rearWheel.DiskBrake = value;
}
}
The intended usage of this class is:
Bicycle bicycle = new()
{
FrontWheelSpokes = 32,
RearWheelSpokes = 24,
FrontWheelDiskBrake = true,
RearWheelDiskBrake = false
};
Unfortunately this code doesn't compile. I get four compile errors in the init => _xxxWheel.Yyy = value;
lines:
Init-only property or indexer 'Wheel.Spokes' can only be assigned in an object initializer, or on 'this' or 'base' in an instance constructor or an 'init' accessor.
Is anything that I can do to fix the compile errors, without compromising the "init-only ness" of all properties in both the Wheel
and Bicycle
classes?
Constraints:
Wheel
class to the outside world. Only the Bicycle
itself should instantiate its wheels.Bicycle
public API is optimal as is. I don't want to change it.It is possible to recreate the instance of your wheel property in every init-setter. You have to copy the properties that you do not set. This has the strong disadvantage that you have to call a lot of unnecessary Wheel constructors, but you can keep your class design. The code might be (for brevity, only with front wheel):
class Bicycle
{
private readonly Wheel _frontWheel = new();
public int FrontWheelSpokes
{
get => _frontWheel.Spokes;
init => _frontWheel = new Wheel
{
Spokes = value,
DiskBrake = _frontWheel.DiskBrake
};
}
public bool FrontWheelDiskBrake
{
get => _frontWheel.DiskBrake;
init => _frontWheel = new Wheel
{
Spokes = _frontWheel.Spokes,
DiskBrake = value
};
}
}
Online-demo: https://dotnetfiddle.net/LzMdP5