Reputation: 12833
I have a variation on a Quantity (Fowler) class that is designed to facilitate conversion between units. The type is declared as:
public class QuantityConvertibleUnits<TFactory>
where TFactory : ConvertableUnitFactory, new() { ... }
In order to do math operations between dissimilar units, I convert the right hand side of the operation to the equivalent Quantity of whatever unit the left hand side is in, and do the math on the amount (which is a double) before creating a new Quantity. Inside the generic Quantity class, I have the following:
protected static TQuantity _Add<TQuantity>(TQuantity lhs, TQuantity rhs)
where TQuantity : QuantityConvertibleUnits<TFactory>, new()
{
var toUnit = lhs.ConvertableUnit;
var equivalentRhs = _Convert<TQuantity>(rhs.Quantity, toUnit);
var newAmount = lhs.Quantity.Amount + equivalentRhs.Quantity.Amount;
return _Convert<TQuantity>(new Quantity(newAmount, toUnit.Unit), toUnit);
}
protected static TQuantity _Subtract<TQuantity>(TQuantity lhs, TQuantity rhs)
where TQuantity : QuantityConvertibleUnits<TFactory>, new()
{
var toUnit = lhs.ConvertableUnit;
var equivalentRhs = _Convert<TQuantity>(rhs.Quantity, toUnit);
var newAmount = lhs.Quantity.Amount - equivalentRhs.Quantity.Amount;
return _Convert<TQuantity>(new Quantity(newAmount, toUnit.Unit), toUnit);
}
... same for multiply and also divide
I need to get the typing right for a concrete Quantity, so an example of an add op looks like:
public static ImperialLengthQuantity operator +(ImperialLengthQuantity lhs, ImperialLengthQuantity rhs) { return _Add(lhs, rhs); }
The question is those verbose methods in the Quantity class. The only change between the code is the math operator (+, -, *, etc.) so it seems that there should be a way to refactor them into a common method, but I am just not seeing it.
How can I refactor that code?
Cheers,
Berryl
Upvotes: 1
Views: 1012
Reputation: 25563
You could write an
protected static TQuantity _Operator<TQuantity>(TQuantity lhs, TQuantity rhs,
Func<double, double, double> op)
where TQuantity : QuantityConvertibleUnits<TFactory>, new()
{
var toUnit = lhs.ConvertableUnit;
var equivalentRhs = _Convert<TQuantity>(rhs.Quantity, toUnit);
var newAmount = op(lhs.Quantity.Amount,equivalentRhs.Quantity.Amount);
return _Convert<TQuantity>(new Quantity(newAmount, toUnit.Unit), toUnit);
}
and call this function in your _Add
, etc. using (d1, d2) => d1 + d2
as an additional parameter.
Upvotes: 4
Reputation: 1063013
There is no direct generic operator support in C#. You can fake it in C# 4.0 on .NET 4 using dynamic
- i.e.
TQuantity newAmount = (dynamic)lhs.Quantity.Amount -
(dynamic)equivalentRhs.Quantity.Amount;
Or you can do it in .NET 3.5 and above using MiscUtil which provides an Operator
class with utility methods (which supports custom and inbuilt operators):
TQuantity newAmount = Operator.Add(lhs.Quantity.Amount,
equivalentRhs.Quantity.Amount);
Alternatively; provide an ICalculator<T>
interface and write implementations per-type.
Upvotes: 0