In your example, you calculate the value when you call
a method that sets the dependent data. While that's
ok, I've experienced a number of situations where doing
that can impose unneeded overhead (namely where the
calculated result is dependent on multiple values that
are also exposed as properties, and where setting any one
of them effectively invalidates the cached result).
What I have done in some complicated cases in order to
avoid needless calculation, is use a boolean flag as a
signal that indicates the calculation needs to be done.
That pattern can be useful when the calcuation is very
expensive and dependent on multple values that can be
set independently (namely other read/write properties
whose values are used in the calcuation), as would be
the case in a well-designed interface.
In this example, a class exposes two 'calculated' properties
called 'Weight' and 'Volume'. While the calculations here are
actually not very expensive in reality, let's assume otherwise,
and that they require significant computational overhead.
public class Box
{
private double width;
private double height;
private double length;
// I use two leading underscores as a reminder
// that this member should never be referenced
// directly, other than from its corresponding
// property setter/getter:
private double __volume;
// true = volume must be recalcuated:
private bool volume_dirty = true;
private double density;
private double __weight;
// true = weight must be recalcuated:
private bool weight_dirty = true;
/// Required validation is done in property setters,
/// so we leverage that from the constructor:
public Box( double length, double width, double height, double density )
{
this.Width = width;
this.Length = length;
this.Height = height;
this.Density = density;
}
// Common validation
void CheckIsGreaterThanZero( double value )
{
if( value < 0.000001 )
throw new ArgumentException("Value must be reasonably positive and non-zero");
}
public double Width
{
get
{
return this.width;
}
set
{
CheckIsGreaterThanZero( value );
this.width = value;
this.volume_dirty = true;
}
}
public double Length
{
get
{
return this.length;
}
set
{
CheckIsGreaterThanZero( value );
this.length = value;
this.volume_dirty = true;
}
}
public double Height
{
get
{
return this.height;
}
set
{
CheckIsGreaterThanZero( value );
this.height = value;
this.volume_dirty = true;
}
}
public double Density
{
get
{
return this.density;
}
set
{
CheckIsGreaterThanZero( value );
this.density = value;
this.weight_dirty = true;
}
}
// Let's assume the calculations needed to
// produce these two values are very expensive:
public double Volume
{
get
{
if( this.volume_dirty )
{
this.__volume = length * width * height;
volume_dirty = false;
}
return this.__volume;
}
}
public double Weight
{
get
{
if( this.weight_dirty )
{
this.__weight = this.density * this.Volume; // <--- use the Volume property, not the field
this.weight_dirty = false;
}
return this.__weight;
}
}
}
The advantage of the above approach is that it will not
trigger a recalcuation for each assignment to the four
dependent properties (Width, Height, Length and Density),
so if a consumer were to set all of them, there wouldn't
be a recalculation done for each assignment:
public Box box = new Box( 2.0, 4.0, 6.0, 0.25 );
// These assignments will not trigger any internal calcuations:
box.Width = 3.25;
box.Height = 12.0;
box.Length = 5.253;
box.Density = 0.3125
// The following line triggers the calcuation of
// both the volume and weight, in that order:
console.WriteLine(" The weight of the box is {0}", box.Weight );
The one point that is not obvious, is that even from within
the class, one would never reference the private '__volume'
or '__weight' fields because their values may not be valid at
any given point (and that's why I use two leading underscores
to remind me of it). So even from within the class, the public
property would be used to get the corresponding values, as
the setter for the Weight property gets the calculated volume
in the example.
Taking this approach is useful when using data binding,
because in some cases the value of properties can be
referenced frequently (like from the Paint handler of the
property grid).
I am writing, in C#, some classes for a project that I am playing with and wanted to get some input on read-only properties versus returning values via a method call.
As as simple example
private int mReadOnlyA;
private int mReadOnlyB;
public int A()
{
return mReadOnlyA;
}
public int B
{
get {return mReadOnlyB;}
}
public int Foo(int Input)
{
// A and B are calculated here based on Input
}
Is one way any better or any worse than the other way? Are there benefits or problems with one or the other that I have yet to see?