Какое исключение выбрали из средства настройки?

У меня есть свойство строки, которое имеет требование максимальной длины, потому что данные связаны с базой данных. Какое исключение следует делать, если вызывающий объект пытается установить строку, превышающую эту длину?

Например, этот код С#:

public string MyProperty
{
    get
    {
        return _MyBackingField;
    }
    set
    {
        if (value.Length > 100)
            throw new FooException("MyProperty has a maximum length of 100.");

        _MyBackingField = value;
    }
}

Я считал ArgumentException, но это просто не кажется правильным. Технически это функция - MyProperty_set(string value) - поэтому можно сделать случай для ArgumentException, но это не называется функцией для глаз потребителя - это с правой стороны оператора присваивания.

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

Ответ 1

Посмотрите на mscorlib.dll с Reflector, в аналогичной ситуации, такой как System.String.StringBuilder.Capacity. Microsoft использует ArgumentOutOfRangeException(), аналогичный:

public int PropertyA
{
    get
    {
        return //etc...
    }
    set
    {
        if (condition == true)
        {
            throw new ArgumentOutOfRangeException("value", "/* etc... */");
        }
        // ... etc
    }
}

Ответ 2

Мне ArgumentException (или дочерний) имеет больше смысла, потому что аргумент (значение), который вы предоставили, недействителен, и это то, что было создано ArgumentException для.

Ответ 3

Я бы вообще не выбрал исключение. Скорее я бы допустил строку любой длины и затем имел отдельный метод "Validate" в классе, который вызывается перед сохранением. Существует несколько сценариев, особенно если вы используете привязку данных, в которой исключение исключений из настроек свойств может привести вас к беспорядку.

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

Процитировать в Microsoft Рекомендации по разработке для создания библиотек классов:

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

Ответ 4

Помните, сколько проблем в информатике разрешено путем добавления дополнительного уровня косвенности?

Один из подходов - создать новый тип FixedLengthString. Это будут экземпляры этого типа, которые проверяют длины строк, которые они инициализируют, с помощью оператора преобразования для преобразования типов из простой строки. Если ваш установщик свойств принимает такой тип, как его аргумент, любое нарушение станет исключением преобразования типа вместо исключения аргумента/свойства.

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

Ответ 5

public IPAddress Address
{
    get
    {
        return address;
    }
    set
    {
        if(value == null)
        {
            throw new ArgumentNullException("value");
        }
        address = value;
    }
}

через MSDN

Ответ 6

Вы можете использовать InvalidOperationException. Это компромисс. Я также не стал бы использовать исключение ArgumentException.

Ответ 7

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

При отбрасывании InvalidOperationException отображается значение, переданное этому установщику.