Zainspirowany przez Units of Measure in F# i pomimo potwierdzenia (here), że nie można tego zrobić w języku C#, miałem pomysł na drugi dzień, z którym bawiłem się.Jednostki miary w C# - prawie
namespace UnitsOfMeasure
{
public interface IUnit { }
public static class Length
{
public interface ILength : IUnit { }
public class m : ILength { }
public class mm : ILength { }
public class ft : ILength { }
}
public class Mass
{
public interface IMass : IUnit { }
public class kg : IMass { }
public class g : IMass { }
public class lb : IMass { }
}
public class UnitDouble<T> where T : IUnit
{
public readonly double Value;
public UnitDouble(double value)
{
Value = value;
}
public static UnitDouble<T> operator +(UnitDouble<T> first, UnitDouble<T> second)
{
return new UnitDouble<T>(first.Value + second.Value);
}
//TODO: minus operator/equality
}
}
Przykład użycia:
var a = new UnitDouble<Length.m>(3.1);
var b = new UnitDouble<Length.m>(4.9);
var d = new UnitDouble<Mass.kg>(3.4);
Console.WriteLine((a + b).Value);
//Console.WriteLine((a + c).Value); <-- Compiler says no
Następnym krokiem jest trudny do realizacji konwersje (fragment)
public interface IUnit { double toBase { get; } }
public static class Length
{
public interface ILength : IUnit { }
public class m : ILength { public double toBase { get { return 1.0;} } }
public class mm : ILength { public double toBase { get { return 1000.0; } } }
public class ft : ILength { public double toBase { get { return 0.3048; } } }
public static UnitDouble<R> Convert<T, R>(UnitDouble<T> input) where T : ILength, new() where R : ILength, new()
{
double mult = (new T() as IUnit).toBase;
double div = (new R() as IUnit).toBase;
return new UnitDouble<R>(input.Value * mult/div);
}
}
(chciałbym uniknąć uruchamianiu obiektów za pomocą statycznego, ale jak wszyscy znamy can't declare a static method in an interface)) Możesz to zrobić:
var e = Length.Convert<Length.mm, Length.m>(c);
var f = Length.Convert<Length.mm, Mass.kg>(d); <-- but not this
Oczywiście, jest w tym luka, w porównaniu do F # Jednostek miary (pozwolę ci to rozpracować).
Och, pytanie brzmi: co o tym sądzisz? Czy warto go używać? Czy ktoś już zrobił coś lepszego?
UPDATE dla osób zainteresowanych w tym obszarze tematycznym, here jest link do papieru od 1997 omawiania innego rodzaju rozwiązania (nie specjalnie dla C#)
Spójrz na kalkulator Frink i język programowania Frink. –
Zastanawiam się, czy ktoś podszedł do jednostek w C# z atrybutami dla wartości właściwości klasy. – ja72
Frink to bomba dla tego typu problemu. –