Как стать автором
Обновить

Комментарии 24

Кат бы повыше…
Только синтаксис C# не позволит писать так в аттрибутах.

Как это не позволяет?!


public class Sensor
{
    public SensorType Type { get; set; }

    [Number(Type = SensorType.Temperature, Min = 200, Max = 600, Force = 273)]
    [Number(Type = SensorType.Voltage, Min = -400, Max = 400, Force = 0)]
    public decimal Value { get; set; }
}

public enum SensorType
{
    Temperature,
    Voltage
}

[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
class NumberAttribute : Attribute
{
    public SensorType Type { get; set; }
    public int Min { get; set; }
    public int Max { get; set; }
    public int Force { get; set; }
}

От чего зависит свойство мы не сможем задать. Конкретно тут это “Type” — это свойство динамическое. Зависеть свойство может от любого другого поля в классе, а в другом классе вообще другие поля.А атрибут должен работать с разными классами. Это в JavaScript можно задавать то, что не объявлено. А тут вы не сможете в атрибуте прописать все поля от которых может зависить свойство. Вторая проблема, почему числа прописывается в строках — нельзя в атрибутах пользоваться decimal.

Вы недостаточно хорошо описали задачу, раз требуются дополнительные пояснения.
Едва ли для аналоговых датчиков точность представления double перестанет Вас устраивать.
Хоть про decimal и написанно, что хорошо подходит для финансовых расчетов, для любых других подсчетов которые помещаются на дисплее датчика использовать необходимо только decimal. Пример:
    for (int i = 0; i < 10000; i++)
    {
        sumDouble += 0.001;
        sumDecimal += 0.001m;
    }

Так вот в double сумма не будет равна 10, а decimal будет.
А вот что это за 0.001 может быть:
  • моментальное потребление в 1 литр, и мы считаем потребление за почти три часа(10000 сек) и 10 кубометров не получается
  • это может быть шаг в поле принимающем значение от 0 до 10 в пользовательском интерфейсе, и при каком-то из нажатий стрелочки вверх вместо числа с тремя знаками после запятой, мы получим кучу девяток в хвосте

Примеров можно придумать много. Но все что можно или нужно представлять в десятичных дробях необходимо считать в decimal.
Эти ограничения довольно легко обходятся. Decimal — это большое целое и смещение десятичной запятой. При остром желании парой (long;int) можно описать всё что надо.

PS: У Вас в примере всё равно только целые числа фигурировали…
Только синтаксис C# не позволит писать так в аттрибутах.

Эммм… Кто Вам такое сказал? Именованные свойства называется.

Не получится прописать все свойства от которых можно строить зависимости, это необходимо прописывать гибко. Строки подходят для описания зависимостей

Больше похоже на вопрос архитектуры, но не технические ограничения.
Валидация формата строк в атрибутах — унос потенциальных ошибок в рантайм.
«Головная боль при разработке и поддержке» — хорошее описание вашего финального велосипеда. У вас не возникало мысли, что где-то перемудрили, когда всё это изобретали? Задача верификации — не сложная, разжеванная и вполне решаема не write-only способом.
Вот в том то и дело, что с точки зрения того, кто будет пользоваться такой моделью, все очень просто. Поправил атрибут или повесил новый — и оно само работает. А вот как именно это работает наружу не вылезает. Ну как минимум за пол года никого не волновало. А вот предметная логика (то как зависят свойства друг от друга) собраны в одном месте и читабельны.
Но рано или поздно любой код приходится либо поддерживать, либо выкидывать. В данном случае второе выйдет дешевле.

Забавно, что статья называется "Динамическое аспектно-ориентированное", но что именно?

Для решаемой задачи идеально подходит язык Ada, ещё можно добавить использование SPARK (типы-подмножества, игры с точностью, контрактное программирование, доказательства правильности, ...).
В этой статье люди описывают создание своих велосипедов на C#. Ну ок, так тоже можно.
Вроде как с помощью Roslyn можно дополнить C# нужными вещами?

Более того, для .net существует язык F# в котором есть Units & Union types.

Можно написать конечный автомат, используя при этом шаблон проектирования «Состояние».
Мне кажется или все трудности автора происходят от недостаточной проработанности предметной области? Разработка самодостаточных типов данных обычно приводит к значительному упрощению алгоритмов.

Например, можно было ввести типы Voltage и Temperature, ограничения на значения ввести внутри них, а в класс Sensor добавить аргумент типа Sensor.
В том то и дело, что предметная область не ложится на обычную обьектно-ориентированную модель.
image
Если ввести типы (Voltage и Temperature), то не плохо было бы еще унаследовать от них датчики конкретных производителей (например «Huaweo» и «Deck», где перые имеют подстройку, а вторые нет — Adjustment==0), потом унаследовать от них линейки датчиков(«Common» и «Flex» где вторые могут не просто измерять, а вычислять средние показатели за настроенный интервал — Interval!=0) — получатся классы типа VoltageDeckFlex в котором можно прописать конкретные модели с их возможными параметрами. При этом выяснится что у всех датчиков Flex по стандарту одинаковые ограничения для температурных и для напряжения, а классов VoltageFlex и TemperatureFlex нет и прописывать придется во всех классах (VoltageDeckFlex, VoltageHuaweoFlex, TemperatureDeckFlex, TemperatureHuaweoFlex)
С описанием же через атрибуты такой проблемы не возникнет
public class Sensor
{
    public virtual SensorType Type { get; set; }

    public virtual CompanyType Company{ get; set; }

    public virtual ModelType Model{ get; set; }

    [Number("Company=Huaweo", "0")]
    [Number("Company=Deck", "-10..10", Force = "0")]
    public virtual decimal Adjustment{ get; set; }

    [Number("", "0")]
    [Number("Model=Flex", "0..100", Force = "0")]
    public virtual decimal Interval{ get; set; }

    [Number("Type=Temperature", "200..600")]
    [Number("Type=Voltage", "-400..400")]    
    [Number("Type=Voltage;Company=Deck;Model=Flex", "-600..600")]
    public virtual decimal Value { get; set; }
}

Вторая проблема — если пользователь заполнил настройку, а потом выяснил что модель у него другая — надо класс менять.
Вы хотите сказать, что параметры физических элементов хардкодятся, а не выносятся в настройки?..
Абсолютно согласен, могли бы, и реализовывались легко бы. Но в конкретно моем случае, это вещи которые нельзя выдавать пользователям. А если описывать во внутренних ресурсах, то не нашлось причин разделять класс и его ограничения.
Да и нагружать статью поставкой правил из конфигов, думаю лишнее — и так довольно тяжелая статья вышла
В том то и дело, что предметная область не ложится на обычную обьектно-ориентированную модель.
Предметная область не ложится на обычную обьектно-ориентированную модель для C#, если взять более мощный язык в области ООП, то будет легче.

А что, более вменяемо прямо совсем никак?


Ну, например


public sealed class Sensor {
    public static Sensor Voltage() => new Sensor(SensorType.Voltage, -400, 400);
    public static Sensor Temperature() => new Sensor(SensorType.Temperature, 200, 600);

    Sensor(SensorType type, decimal min, decimal max) {
        Type = type;
        this.min = min;
        this.max = max;
    }
    readonly decimal min;
    readonly decimal max;
    public SensorType Type { get; }
    decimal value;
    public decimal Value {
        get { return value; }
        set {
            this.value = Max(Min(value, max), min);
        }
    }
}
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории