Лучшее исключение для недопустимого аргумента типа общего типа

В настоящее время я пишу код для 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 звучит логично, но это аргумент типа, а не обычный аргумент, который может легко путать вещи. Должен ли я представить свой собственный класс TypeArgumentException? Использовать InvalidOperationException? NotSupportedException? Что-нибудь еще?

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

Ответ 1

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

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

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

Учитывая цель Unconstrained Melody...

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

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

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

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

Ответ 2

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

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

Ответ 3

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

Обновление

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

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

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

Ответ 4

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

Ответ 5

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

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

Ответ 6

Id перейдите в NotSupportedExpcetion.

Ответ 7

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

Ответ 8

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

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

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

Ответ 9

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

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

Если пользователь пытался передать что-то, что не было перечислением, я бы выбрал исключение InvalidOperationException.

Edit:

Другие поднимают интересный момент, что это не поддерживается. Моя единственная проблема с NotSupportedException заключается в том, что обычно это исключения, которые бросаются, когда "темная материя" вводится в систему или, говоря иначе: "Этот метод должен войти в систему на этом интерфейсе, но мы выиграли" включите его до версии 2.4"

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

Изменить 2:

Еще один возможный вариант:

System.ComponentModel.InvalidEnumArgumentException  

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

Ответ 10

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