An alternative to using a case
would be to write some kind of class to do the mapping, for example:
public sealed class CostsPerWeight
{
class CostPerWeight
{
public int Low;
public int High;
public double Cost;
}
readonly List<CostPerWeight> costs = new List<CostPerWeight>();
public CostsPerWeight Add(int low, int high, double result)
{
// Error handling omitted for brevity.
// Real code should check that low < high and that ranges do not overlap.
costs.Add(new CostPerWeight { Low = low, High = high, Cost = result } );
return this;
}
public double Cost(int weight)
{
// This throws if the weight isn't in the list.
// If that's not what you want, you'd have to add extra error handling here.
return costs.First(x => x.Low <= weight && weight <= x.High).Cost;
}
}
Which you would use like this (I've used doubles instead of strings for the costs for this example, but you can use whatever type you need):
var costs = new CostsPerWeight()
.Add( 0, 2, 3.69)
.Add( 3, 4, 4.86)
.Add( 5, 6, 5.63)
.Add( 7, 8, 5.98)
.Add( 9, 10, 6.28)
.Add(11, 30, 15.72);
double shippingCost = costs.Cost(weight);
If you have a lot of these switch statements in VB, it would be worth considering this approach.
(The advantage of using this instead of a Linq one-liner is simply that it's easier to document and unit test. You could also create a CostsPerWeight
class instance and pass it around - useful for decoupling code, dependency-injection and for unit testing.)
It does seem to me that the concept of looking up a cost based on a weight is crying out to be encapsulated in a class, rather than embedded piecemeal in various parts of the code.
Here's a more extended example of CostsPerWeight
with more error handling:
public class CostsPerWeight
{
class CostPerWeight
{
public int Low;
public int High;
public double Cost;
}
readonly List<CostPerWeight> costs = new List<CostPerWeight>();
double min = double.MaxValue;
double max = double.MinValue;
double costForMin;
public CostsPerWeight Add(int low, int high, double cost)
{
if (low > high)
throw new ArgumentException(nameof(low) + " must be less than " + nameof(high));
if (cost < 0)
throw new ArgumentOutOfRangeException(nameof(cost), "cost must be greater than zero");
costs.Add(new CostPerWeight { Low = low, High = high, Cost = cost } );
if (low < min)
{
min = low;
costForMin = cost;
}
if (high > max)
max = high;
return this;
}
public double Cost(int weight)
{
if (weight < min)
return costForMin;
if (weight > max)
throw new InvalidOperationException($"Weight {weight} is out of range: Must be <= {max}");
return costs.First(x => x.Low <= weight && weight <= x.High).Cost;
}
}