Как избежать элегантно примитивной одержимости в C # - PullRequest
1 голос
/ 16 октября 2019

Для класса Foo мне нужно свойство типа int SanityCheckPeriod, которое допускает только значения между двумя пределами (скажем, от 1 до 7).

Какой элегантный способ реализовать это требование - возможно,с атрибутами в декларативной форме? (потому что мне нужен этот шаблон несколько раз, и для выразительности было бы здорово увидеть ограничения, непосредственно связанные со свойством.

Идея будет выглядеть примерно так:

public class Foo
{  
    [RangeAttribute(min: 1, max: 7)]
    public Period SanityCheckPeriod { get; }
    ...
}


public class Period
{
    private int _days;

    private int _max;
    private int _min;

    public int Days
    {
        get => _days;
        private set
        {
            if (_min <= value) 
                throw new ArgumentExcpetion($"Period must be equal or larger than {_min} day(s).");
            if (value <= _max)
                throw new ArgumentExcpetion($"Period must be equal or smaller than {_max} days.");
            _days = value;
        }
    }

    public Period(int days)
    {
        // access the RangeAttribute here
        // how to do? 
        // and set _min and _max
    }
}


[AttributeUsage(AttributeTargets.Property)]
public class RangeAttribute : Attribute
{
    public int Min { get; }
    public int Max { get; }

    public RangeAttribute(int min, int max)
    {
        Min = min;
        Max = max;
    }
}

Ответы [ 3 ]

0 голосов
/ 16 октября 2019

Если вам нужны ТОЛЬКО точные и общеизвестные проверки работоспособности, вы можете выбрать методы расширения:

public static void SanityCheckPeriod(this int value, int min, int max)
{
    //check sanity
}

В общем, элегантный способ добиться этого - это Аспектно-ориентированное программирование, в котором C # не поддерживает OOTB,PostSharp хорошо документирован (я не связан с ними), но я не знаю, удовлетворяет ли какая-либо из их лицензий вашим потребностям.

Если вы предпочитаете привнести свой собственный аспект, то вам придется принятьчто вам нужно получить доступ к вашему объекту через «интерпретатор».

Я видел пример, когда все объекты доступны через фабрику, где все возвращаемые объекты являются обертками, которые сканируют объект на предмет пользовательских атрибутов. Таким образом, именно в этом случае предпочтительным является аспектно-ориентированный код BYO, а грубый код скрыт в одном месте, а остальная часть кода остается элегантной, и это тоже решение.

0 голосов
/ 16 октября 2019

С подсказкой @rzmoz это было так просто:

  1. Установить Инструменты PostSharp для Visual Studio
  2. Добавить пакеты NuGet
    • PostSharp.Patterns.Model с RangeAttribute
    • PostSharp с компилятором ткачества кода
  3. Применить RangeAttribute в собственность

    [Range(1, 7)]
    public int SanityCheckPeriod { get; internal set; }
    
  4. Скомпилируйте материал и все работает как положено

Совет: свойство не может быть доступно только для чтения и имеет private setter modifier R # жалуется Авто-свойство может быть сделано только для получения и рекомендует его удалить. Но тогда плетение не сработает. Вместо того, чтобы подавить эту подсказку, я переключился на модификатор internal, который не будет генерировать эту подсказку R # .

0 голосов
/ 16 октября 2019

Я предполагаю, что вы не работаете в контексте платформы, которая уже предоставляет соглашения о валидации (как показано в MVC Часть 6: Использование аннотаций данных для валидации модели ).

Я бы выбрал следующее:

public int Days
    {
        get => _days;
        private set { 
            Ensure(1,7);
            _days = value;
        }
    }

private void Ensure(int min, int max, [System.Runtime.CompilerServices.CallerMemberName] string memberName) 
{
  if (_min < value) 
     throw new ArgumentExcpetion($"'{memberName}' must be equal or greater than {min}.");
  if (value < max)
     throw new ArgumentExcpetion($"'{memberName}' must be equal or smaller than {max}.");
}

(обратите внимание, что я настроил <= и >= в соответствии с сообщениями об ошибках.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...