Лучшее исключение для недопустимого аргумента универсального типа - PullRequest
97 голосов
/ 11 сентября 2009

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

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

Просто чтобы сделать этот бетон, если у меня есть что-то вроде этого:

// Returns a value with all bits set by any values
public static T GetBitMask<T>() where T : struct, IEnumConstraint
{
    if (!IsFlags<T>()) // This method doesn't throw
    {
        throw new ???
    }
    // Normal work here
}

Какое лучшее исключение бросить? ArgumentException звучит логично, но это аргумент type , а не обычный аргумент, который может легко запутать вещи. Должен ли я представить свой собственный класс TypeArgumentException? Использовать InvalidOperationException? NotSupportedException? Что-нибудь еще?

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

Ответы [ 11 ]

42 голосов
/ 11 сентября 2009

NotSupportedException звучит , как будто он явно подходит, но в документации четко указано, что его следует использовать для других целей. Из замечания класса MSDN:

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

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

С учетом цели Неограниченная мелодия ...

Существуют различные полезные вещи, которые можно сделать с помощью общего методы / классы, где есть ограничение типа "T: enum" или "T: делегат "- но, к сожалению, это запрещено в C #.

Эта служебная библиотека обходит запреты, используя ildasm / ilasm ...

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

Должны ли клиенты быть в состоянии отличить это от исключений BCL? Когда клиент может случайно позвонить, используя ваниль enum? Как бы вы ответили на вопросы, поставленные принятым ответом на Какие факторы следует учитывать при написании пользовательского класса исключений?

23 голосов
/ 11 сентября 2009

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

Я думаю, InvalidOperationException - наиболее подходящее исключение, которое вы можете здесь сгенерировать

12 голосов
/ 11 сентября 2009

Общее программирование не должно генерировать во время выполнения для недопустимых параметров типа. Он не должен компилироваться, вы должны иметь принудительное время компиляции. Я не знаю, что содержит IsFlag<T>(), но, возможно, вы можете превратить это в принудительное выполнение во время компиляции, например, попытаться создать тип, который возможно создать только с помощью 'flags'. Возможно, класс traits может помочь.

Обновление

Если вы должны бросить, я бы проголосовал за исключение InvalidOperationException. Причина заключается в том, что универсальные типы имеют параметры , а ошибки, связанные с параметрами (метода), сосредоточены вокруг иерархии ArgumentException. Однако рекомендация для ArgumentException гласит, что

если сбой не связан с сами аргументы, то InvalidOperationException должно быть б.

В этом есть хотя бы один скачок веры, что рекомендации метода параметров параметров также должны применяться к универсальным параметрам, но в иерархии SystemException нет ничего лучше IMHO.

9 голосов
/ 11 сентября 2009

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

8 голосов
/ 11 сентября 2009

Я бы пошел с NotSupportedException. В то время как ArgumentException выглядит нормально, это действительно ожидается, когда аргумент, переданный методу, является неприемлемым. Аргумент типа - это определяющая характеристика для фактического метода, который вы хотите вызвать, а не реальный «аргумент». InvalidOperationException должен быть выдан, если выполняемая операция в некоторых случаях может быть действительной, но для конкретной ситуации это недопустимо.

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

6 голосов
/ 15 февраля 2016

Очевидно, Microsoft использует для этого ArgumentException, как показано на примере Expression.Lambda <> , Enum.TryParse <> или Marshal.GetDelegateForFunctionPointer <> в разделе «Исключения». Я также не смог найти ни одного примера, указывающего на обратное (несмотря на поиск в локальном справочном источнике TDelegate и TEnum).

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

Надеюсь, это решит вопрос раз и навсегда.

3 голосов
/ 11 сентября 2009

Идентификатор идет с NotSupportedExpcetion.

2 голосов
/ 11 сентября 2009

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

1 голос
/ 12 сентября 2009

Я бы также проголосовал за InvalidOperationException. Я выполнил (неполную) блок-схему .NET директив по созданию исключений на основе Руководства по проектированию фреймворков 2-е издание. некоторое время назад, если кому-то интересно.

1 голос
/ 11 сентября 2009

Как насчет наследования от NotSupportedException. Хотя я согласен с @Mehrdad в том, что в этом есть смысл, я слышал ваше мнение о том, что оно не совсем подходит. Так что унаследуйте от NotSupportedException, и таким образом люди, кодирующие ваш API, все еще могут перехватить NotSupportedException.

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