Generic using Arithmetic #1528
-
I want to create a type in my application that is a generic over unit types and allows arithmetic. Something like this: public class Range<T> where T : UnitsNet.IQuantity, IComparable // I want this to also have IArithmeticQuantity
{
public T Start {get; internal set;}
public T Stop {get; internal set;}
public Range(T start, T stop) {
// I don't think this is necessary - but it is
// the only way I could think of that would allow me to
// do arithmetic on start/stop in the same base unit.
if (start.Unit != stop.Unit) {
stop = (T)stop.ToUnit(start.Unit);
}
if (stop.CompareTo(start) < 0) {
throw new ArgumentOutOfRangeException(nameof(stop), $"The 'stop' value must be greater than the 'start' value: ${start} < ${stop}");
}
Start = start;
Stop = stop;
}
public T GetSpan() {
// Here I want to do 'Stop - Start' but have it
// return in the same unit type.
// return T.From(....) ?
// `return Stop - Start` doesn't work.
// I can't seem to add `IArithmeticQuantity` to the type constraint on `T`
}
public Range<T> Shift(T amount) {
/// Here I want to add `amount` to start/stop and return a new Range.
}
// etc for other ops.
} The goal would be to have something like: var R = new Range<Frequency>(
Frequency.FromHertz(10),
Frequency.FromKiloHertz(100)
);
var R2 = R.Shift(Frequency.FromHertz(50)); The trouble I'm having is figuring out how to do arithmetic over the type Is there another way to do arithmetic over a generic type |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Hi, late reply sorry. The first thing I spot in your example is Generally though, you'll have to provide both Here is a revised example, I didn't test it but at least it compiles. Give it a go and see if it helps. public class Range<TQuantity, TUnit>
where TQuantity : IArithmeticQuantity<TQuantity, TUnit>, IComparable<TQuantity>
where TUnit : struct, Enum
{
public TQuantity Start { get; internal set; }
public TQuantity Stop { get; internal set; }
public Range(TQuantity start, TQuantity stop)
{
// NOTE: Prone to rounding errors if different units (will convert to base unit internally)
if (stop.CompareTo(start) < 0)
{
throw new ArgumentOutOfRangeException(nameof(stop), $"The 'stop' value must be greater than the 'start' value: ${start} < ${stop}");
}
Start = start;
Stop = stop;
}
public TQuantity GetSpan() => Stop - Start;
public Range<TQuantity, TUnit> Shift(TQuantity amount)
{
return new Range<TQuantity, TUnit>(Start + amount, Stop + amount);
}
// etc for other ops.
} |
Beta Was this translation helpful? Give feedback.
Hi, late reply sorry.
I find generic arithmetic hard, honestly. We have made some attempts to support it: https://github.com/angularsen/UnitsNet/wiki/Experimental:-Generic-Math-and-INumber
The first thing I spot in your example is
class Range<T> : IQuantity
.A quantity is Value+Unit, so saying
Range
is a quantity does not make sense to me.Generally though, you'll have to provide both
TQuantity
andTUnit
.Here is a revised example, I didn't test it but at least it compiles. Give it a go and see if it helps.