Вы пропускаете размерный анализ. Например (из ответа Вы связались с), в F#, можно сделать это:
let g = 9.8<m/s^2>
и это генерирует новую единицу ускорения, полученного из метров и секунды (можно на самом деле сделать то же самое в шаблонах использования C++).
В C#, возможно сделать размерный анализ во времени выполнения, но это добавляет наверху и не приносит Вам пользу времени компиляции, проверяя. Насколько я знаю, что нет никакого способа сделать полные единицы времени компиляции в C#.
, Стоит ли это сделать, зависит от приложения, конечно, но для многих научных приложений, это - определенно хорошая идея. Я не знаю ни о каких существующих библиотеках для.NET, но они, вероятно, существуют.
, Если Вы интересуетесь тем, как сделать это во времени выполнения, идея состоит в том, что каждое значение имеет скалярную величину и целые числа, представляющие питание каждой основной единицы.
class Unit
{
double scalar;
int kg;
int m;
int s;
// ... for each basic unit
public Unit(double scalar, int kg, int m, int s)
{
this.scalar = scalar;
this.kg = kg;
this.m = m;
this.s = s;
...
}
// For addition/subtraction, exponents must match
public static Unit operator +(Unit first, Unit second)
{
if (UnitsAreCompatible(first, second))
{
return new Unit(
first.scalar + second.scalar,
first.kg,
first.m,
first.s,
...
);
}
else
{
throw new Exception("Units must match for addition");
}
}
// For multiplication/division, add/subtract the exponents
public static Unit operator *(Unit first, Unit second)
{
return new Unit(
first.scalar * second.scalar,
first.kg + second.kg,
first.m + second.m,
first.s + second.s,
...
);
}
public static bool UnitsAreCompatible(Unit first, Unit second)
{
return
first.kg == second.kg &&
first.m == second.m &&
first.s == second.s
...;
}
}
, Если Вы не позволяете пользователю изменять значение единиц (хорошая идея так или иначе), Вы могли добавить подклассы для общих единиц:
class Speed : Unit
{
public Speed(double x) : base(x, 0, 1, -1, ...); // m/s => m^1 * s^-1
{
}
}
class Acceleration : Unit
{
public Acceleration(double x) : base(x, 0, 1, -2, ...); // m/s^2 => m^1 * s^-2
{
}
}
Вы могли также определить более определенные операторы на производных типах, чтобы не проверять на совместимые единицы на общих типах.
Используя отдельные классы для различных единиц той же меры (например, cm, мм и ft для Длины) кажется довольно странным. На основе Платформы.NET DateTime и классы TimeSpan, я ожидал бы что-то вроде этого:
Length length = Length.FromMillimeters(n1);
decimal lengthInFeet = length.Feet;
Length length2 = length.AddFeet(n2);
Length length3 = length + Length.FromMeters(n3);
существует jscience: http://jscience.org/ , и вот отличный dsl для единиц: http://groovy.dzone.com/news/domain-specific-language-unit - . iirc, c# имеет закрытия, таким образом, необходимо быть в состоянии мостить что-то.
Почему бы не использовать CodeDom для генерации всех возможных перестановок единиц автоматически? Я знаю, что это не является лучшим - но я буду определенно работать!
Посмотрите Шиканье Ometa (который будет доступен для Шиканья 1.0): Шиканье Ometa и Расширяемый Парсинг
Вы можете добавить методы расширения к числовым типам для генерации показателей. Это будет немного похоже на DSL:
var mass = 1.Kilogram();
var length = (1.2).Kilometres();
На самом деле это не соглашение .NET и, возможно, не самая открываемая функция, поэтому, возможно, вы бы добавили их в специальное пространство имен для людей, которым они нравятся, а также предложили бы больше традиционные методы строительства.