Единицы измерения в C # - почти - PullRequest
57 голосов
/ 08 декабря 2008

Вдохновленный Единицами измерения в F # , и, несмотря на утверждение ( здесь ), что вы не могли сделать это в C #, у меня была идея на днях, что я играл с.

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
    }
}

Пример использования:

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

Следующий шаг - попытка реализовать преобразования (фрагмент):

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);
    }
}

(Я бы хотел избежать создания экземпляров объектов с помощью static, но, как мы все знаем, вы не можете объявить статический метод в интерфейсе ) Затем вы можете сделать это:

var e = Length.Convert<Length.mm, Length.m>(c);
var f = Length.Convert<Length.mm, Mass.kg>(d); <-- but not this

Очевидно, в этом есть зияющая дыра по сравнению с F # Единицами измерения (я позволю вам разобраться).

О, вопрос: что вы думаете об этом? Это стоит использовать? Кто-то уже сделал лучше?

ОБНОВЛЕНИЕ для людей, заинтересованных в этой предметной области, здесь - ссылка на статью 1997 года, в которой обсуждается другой тип решения (не специально для C #)

Ответы [ 12 ]

0 голосов
/ 29 января 2009

См. Boo Ometa (которая будет доступна для Boo 1.0): Boo Ometa и расширяемый разбор

0 голосов
/ 08 декабря 2008

Почему бы не использовать CodeDom для автоматической генерации всех возможных перестановок блоков? Я знаю, что это не самое лучшее, но я обязательно буду работать!

...