I first ask your help for a class representing a toothed wheel. I would like that when the value of the Z or m_0 properties changes, the Update() procedure runs automatically in order to perform an update of the d_0 property. However I do not want to perform the calculation directly in the get block because the example I took is simple but some calculations will be particularly long to process and I do not want to repeat the calculation each time I try to read the property.
public class ToothedWheel
{
public ToothedWheel(int Z = 16, double m_0 = 8)
{
this.Z = Z;
this.m_0 = m_0;
}
public void Update()
{
d_0 = m_0 * Z;
}
public int Z { get; set; } // Z Tooth number
public double m_0 { get; set; } // m_0 Module (mm)
public double d_0 { get; private set; } // Pitch diameter (mm)
}
I would also need help with a class representing a gear (2 toothed wheels). In this class the value of the property m_0 of the Pinion must be equal to the value of the property m_0 of the Wheel. To achieve this I have defined a get block and a set block however I can still access the m_0 properties by going directly through the ToothedWheel classes. How can I wrap my class properly to allow the Z property to be changed directly through the ToothedWheel class but to avoid the m_0 property from being changed.
public class Gear
{
public Gear()
{
Pinion = new ToothedWheel();
Wheel = new ToothedWheel();
}
public ToothedWheel Pinion, Wheel;
private double _m_0;
public double m_0
{
get { return _m_0; }
set
{
_m_0 = value;
Pinion.m_0 = _m_0;
Wheel.m_0 = _m_0;
}
}
}
I don't know how to solve my problems and I don't find the anwer on the forum.
CodePudding user response:
To make sure that Update
is only called once when the value is requested and repeated requests do not cause extra load you should do something like the below.
Any update to the dependent values m_0
and Z
will force d_0
to be recalculated on the next get access but cause further requests to fallback to the previously calculated value.
public class ToothedWheel
{
private int z;
private double m0;
private double d0;
private bool calculated;
public ToothedWheel(int Z = 16, double m_0 = 8)
{
this.Z = Z;
this.m_0 = m_0;
}
private void Update()
{
d0 = m0 * z;
calculated = true;
}
// Z Tooth number
public int Z
{
get => z;
set
{
if (z != value)
{
z = value;
calculated = false;
}
}
}
// m_0 Module (mm)
public double m_0 {
get => m0;
set
{
if (m0 != value)
{
m0 = value;
calculated = false;
}
}
}
// Pitch diameter (mm)
public double d_0
{
get
{
if (!calculated)
{
Update();
}
return d0;
}
}
}
I would also suggest you use more meaningful property names, e.g.:
Z
=>Teeth
m_0
=>Module
d_0
=>PitchDiameter
It may be more verbose but really will aid readability and maintainability.
CodePudding user response:
First of all:
some calculations will be particularly long to process
Have you measured how long these calculations will take? While avoiding repeated calculations can be a good approach, CPUs are fast, as long as you are doing simple mathematical operations it can do a huge amount of computations in any time measurable for a human.
Hower, computing the value when it is set might cause problems if the value is written to more often than it is read. A common workaround is to do the computation the first time the value is read, and cache it for subsequent reads. You can use a Lazy<T>
for this, recreate the lazy object whenever a parameter is changed, and get the value when it is read.
In this class the value of the property m_0 of the Pinion must be equal to the value of the property m_0 of the Wheel.
Then your classes should enforce this, you can for example use interfaces for this:
public IToothedWheel{
public double m_0 { get; }
}
public class Gear
{
private ToothedWheel pinion;
private ToothedWheel wheel;
private IToothedWheel Pinion => pinion;
private IToothedWheel Wheel => wheel;
public double m_0
{
get { return _m_0; }
set
{
_m_0 = value;
pinion.m_0 = _m_0;
Wheel.m_0 = _m_0;
}
}
}
This should make it impossible for any outsider to make the pinion and wheel value different, at least without checking the runtime type.
Another approach could be to create a graph of components, and use a separate validation checker after any change that will give an error if the arrangement is invalid, and let the user correct the problem.