In writing an insurance premium calculator the basic scheme is as follows: Points are assigned to a predetermined number of attributes, such as car-value, num-incidents-in-past, years-experience-driving etc. Hene, if car worth is $3800, that lies within the 3001 to 4000 range which warrants 30 points in the premium calculation. If num-incidents-in-past is 3 or below, that warrants ZERO points. If 4-5 num-inc then points warranted is 5. If years-exp is between 1-5, that warrants 12 points. The idea is an arbitrary value is being assigned to a range of values for any given number of attributes. The premium calculations is simply tallying up the points warranted for each attribute category and multiplying by some factor i.e 2.5. I am trying to use B. LISKOV'S power of abstractions AND the SRP to neatly assign responsiblities to design a calculator that is extensible and well designed.
Based on the answer provided by drharris here Is there a C# type for representing an integer Range?
How do I access the value out of the following Dictionary whose key is a generic type Range as defined by drharris?
//************************ABSTRACTIONS************************
public abstract class AbsPerson
{
public virtual AbsPolicy APolicy { get; set; }
public virtual string ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public virtual string Address { get; set; }
}
public abstract class AbsPolicy
{
public virtual string PersonID { get; set; } //FK
public virtual int PropValue { get; set; }
public virtual int InsGroup { get; set; }
}
public abstract class AbsValueCategoryCalculator: IEvaluatePolicy
{
//DATA
public abstract void InitRange();
//REFERENCE drharris poster GENERIC TYPE SIGNATURE - public class Range<T> where T : IComparable<T>
public abstract Dictionary<Range<int>, int> ValueRange {get; set;}
public abstract int Tally { get; set; }
//BEHAVIOUR
public virtual void EvaluatePolicyDetails(AbsPerson person)
{
}
}
public interface IEvaluatePolicy
{
void EvaluatePolicyDetails(AbsPerson person);
}
//*************************CONCRETIONS**************************
public class CarValueCategoryCalculator : AbsValueCategoryCalculator
{
public CarValueCategoryCalculator()
{//ctor
InitRange();
}
public override void InitRange()
{
this.ValueRange = new Dictionary<Range<int>, int>();
this.ValueRange.Add(new Range<int>() { Minimum = 1000, Maximum = 2000 }, 10);
this.ValueRange.Add(new Range<int>() { Minimum = 2001, Maximum = 3000 }, 20);
this.ValueRange.Add(new Range<int>() { Minimum = 3001, Maximum = 4000 }, 30);
this.ValueRange.Add(new Range<int>() { Minimum = 4001, Maximum = 5000 }, 40);
this.ValueRange.Add(new Range<int>() { Minimum = 5001, Maximum = 6000 }, 50);
this.ValueRange.Add(new Range<int>() { Minimum = 6001, Maximum = 7000 }, 60);
}
public override Dictionary<Range<int>, int> ValueRange
{
get; set;
}
public override void EvaluatePolicyDetails(AbsPerson person)
{
//I am trying to tally the value given wether the cars worth lies within the range
if (this.ValueRange.ContainsKey(new Range<int>() { Maximum = person.APolicy.PropValue, Minimum = person.APolicy.PropValue }))
{
this.Tally =
}
Console.WriteLine("good");
}
public override int Tally
{
get;set;
}
}//end class
(As noted in comments, Sam's answer points out that a dictionary isn't really what's wanted here - that only finds equal keys, whereas the OP is trying to find a range key that contains a single value. Hash tables just aren't geared up for that.)
You need to either override GetHashCode
and Equals
in Range<T>
(which would be sensible - ideally implementing IEquatable<Range<T>>
at the same time) or create a separate type which implements IEqualityComparer<Range<T>>
and then pass that to the dictionary constructor.
I would probably do it on the range type, like this:
public sealed class Range<T> : IEquatable<Range<T>>
where T : IComparable<T>, IEquatable<T>
{
...
public override int GetHashCode()
{
int hash = 23;
hash = hash * 31 + EqualityComparer.Default<T>.GetHashCode(Minimum);
hash = hash * 31 + EqualityComparer.Default<T>.GetHashCode(Maximum);
return hash;
}
public override bool Equals(object other)
{
return Equals(other as Range<T>);
}
public bool Equals(Range<T> other)
{
if (ReferenceEquals(other, this))
{
return true;
}
if (ReferenceEquals(other, null))
{
return false;
}
return EqualityComparer<T>.Default.Equals(Minimum, other.Minimum) &&
EqualityComparer<T>.Default.Equals(Maximum, other.Maximum);
}
}
Note that currently the Range<T>
type is mutable, however - that's generally a bad idea for dictionary keys. It would be a good idea to make it at least "shallow-immutable" - there's not a lot you can do if the
See more on this question at Stackoverflow