Ограничить значение параметра в конструкторе во время проектирования - PullRequest
6 голосов
/ 25 июля 2010

Я бы хотел ограничить значение числового параметра в конструкторе в определенном диапазоне.

Я знаю, что обычный способ - сделать что-то вроде следующего:

public class Foo
{
    public int MaxAmount { get; }
    public int Amount { get; set; }

    public Foo(int amount)
    {
        if (amount > MaxAmount) { Amount = MaxAmount; }
        else if (amount < 1) { Amount = 1; }
        else { Amount = amount; }
    }
}

Но что мне не нравится в этом, так это то, что вызывающая сторона не знает, когда для свойства установлено значение, отличное от указанного.Я мог бы вернуть исключение вместо того, чтобы молча фиксировать значение, но это не очень дружелюбно.

Что-то, что я хотел бы, - это что-то вроде этого:

public Foo(int(1, this.MaxAmount) amount) // Where int(minimumValue, maximumValue)
{
   Amount = amount;
}

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

Возможно ли что-нибудь подобное?

РЕДАКТИРОВАТЬ ДЛЯ ЯРКОСТИ:

Что мне нужноэто средство, с помощью которого сам параметр может переносить и передавать информацию о своих ограничениях - «запеченным» способом, который, например, может появиться в Intellisense при написании вызова.Таким образом, я бы избегал попыток даже создать экземпляр класса, если значения параметров недопустимы.

Если, например, программа работает, а пользователь вводит число (N) инажимает кнопку, которая создает новый Foo с недопустимым количеством N, теперь у меня есть исключение для обработки и что-то для отладки и исправления.Зачем вообще это позволять?Если Foo был явно определен как имеющий верхнюю границу 4 для своего свойства Amount, какой смысл позволять разработчику писать Foo (5), когда я мог бы сообщить ему, что передаваемое им значение недопустимо в то время, когда оннаписал это?

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

Ответы [ 5 ]

9 голосов
/ 25 июля 2010

Я мог бы вернуть исключение вместо того, чтобы молча фиксировать значение, но это не очень дружелюбно.Что значит "дружелюбный"?Вызывающий не ваш друг, это еще один фрагмент кода, который пытается установить значение вне диапазона.Разработчику, написавшему код, следует немедленно сообщить, что он что-то делает не так.

7 голосов
/ 25 июля 2010

Это можно сделать с помощью проверки статического контракта с помощью Кодовых контрактов (Только Premium - только в стандартной версии предлагается проверка контракта во время выполнения).

Синтаксис просто

public Foo(int amount) {
    Contract.Requires(amount < MaxAmount);
    ...
 }

(Требуется) контракты оцениваются путем проверки того, что аргументы ограничены при вызове метода. В вашем случае будет сложно сравнить аргумент конструктора с полем экземпляра MaxAmount, потому что вы не можете проверить это значение заранее. (Для решения этой проблемы сделайте MaxValue статическим).

Пример такого вызова.

int val = _getFromSomewhere();
var foo = new Foo(val); 
//This May produce compile time error 
// because the contract checker cannot prove you contract is met.

Исправление будет состоять в том, чтобы убедиться, что вы поместили ограничение в то место, где вы вызываете.

int val = _getFromSomewhere();
if (val < Foo.MaxAmount)
    var foo = new Foo(val); 
    //Will always compile fine, because contract is met.

При установке контрактов статическая проверка по умолчанию не включена. В свойствах вашего проекта будет дополнительная вкладка, где вы можете настроить параметры контракта и включить статическую проверку.

2 голосов
/ 25 июля 2010

Вам нужно будет обернуть параметр в новый тип.Интты знают, каково их максимальное количество, и это int.MaxValue.Если это действительно так, что сам параметр знает свою собственную максимальную сумму и что он не является чем-то конкретным для класса Foo, то вам нужно будет создать другой тип, который будет проверять переданную ему сумму.В его нынешнем виде сигнатура конструктора Foo принимает любую структуру данных int.

1 голос
/ 25 июля 2010

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

1 голос
/ 25 июля 2010

Либо сгенерируйте исключение, либо предоставьте статическое свойство для проверки суммы

public static bool ValidateAmount(int amount)
{
    if(amount > MaxAmount)
        return false;
    return true;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...