В настоящее время я пишу код для UnconstrainedMelody, который имеет общие методы, связанные с перечислениями.
Теперь у меня есть статический класс с кучей методов, которые предназначены только для использования с перечислениями «флагов». Я не могу добавить это как ограничение ... поэтому возможно, что они будут вызываться и с другими типами перечислений. В этом случае я хотел бы создать исключение, но я не уверен, какое именно.
Просто чтобы конкретизировать, если у меня есть что-то вроде этого:
// 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
? Что-нибудь еще?
Я бы предпочел не создавать свое собственное исключение для этого, если это явно не правильно.
Ответы:
NotSupportedException
звучит так, как будто он явно подходит, но в документации четко указано, что его следует использовать для другой цели. Из замечаний класса MSDN:Конечно, есть способ, который
NotSupportedException
, очевидно, достаточно хорош, особенно с учетом его здравого смысла. Сказав это, я не уверен, что это правильно.Учитывая предназначение неограниченной мелодии ...
... кажется, что новая
Exception
может быть в порядке, несмотря на тяжелое бремя доказывания, которое мы справедливо должны встретить, прежде чем создавать заказExceptions
. Что-то подобноеInvalidTypeParameterException
может быть полезно для всей библиотеки (а может и нет - это уж точно крайний случай, верно?).Нужно ли будет клиентам отличать это от исключений BCL? Когда клиент может случайно вызвать это, используя ваниль
enum
? Как бы вы ответили на вопросы, поставленные принятым ответом на вопрос Какие факторы следует принимать во внимание при написании настраиваемого класса исключений?источник
InvalidOperationException
неприятные, потому что «Foo просит коллекцию Bar добавить что-то, что уже существует, поэтому Bar бросает IOE» и «Foo просит коллекцию Bar добавить что-то, поэтому Bar вызывает Boz, который бросает IOE, даже если Bar не ожидает этого» оба будут генерировать один и тот же тип исключения; код, который ожидает поймать первое, не будет ожидать второго. Как было сказано ...Foo<T>
как «общий тип» иFoo<Bar>
как «особый тип» в этом контексте, даже если между ними нет отношения «наследования».Я бы избегал NotSupportedException. Это исключение используется в среде, где метод не реализован и есть свойство, указывающее, что этот тип операции не поддерживается. Здесь не подходит
Я думаю, что InvalidOperationException - наиболее подходящее исключение, которое вы можете здесь создать.
источник
T
онenum
украшенFlags
, было бы правильно выбросить NSE.StupidClrException
делает забавное имя;)Универсальное программирование не должно вызывать во время выполнения недопустимые параметры типа. Он не должен компилироваться, у вас должно быть принудительное исполнение во время компиляции. Я не знаю, что
IsFlag<T>()
содержит, но, возможно, вы можете превратить это в принудительное выполнение времени компиляции, например, при попытке создать тип, который можно создать только с помощью «флагов». Возможно,traits
класс может помочь.Обновить
Если вы должны выбросить, я бы проголосовал за InvalidOperationException. Причина в том, что универсальные типы имеют параметры, а ошибки, связанные с параметрами (метода), сосредоточены вокруг иерархии ArgumentException. Однако в рекомендации по ArgumentException указано, что
Есть, по крайней мере, один прыжок веры, рекомендации по параметрам метода также должны применяться к общим параметрам, но в иерархии SystemException, imho, нет ничего лучше.
источник
IsFlag<T>
определяет, применено ли к нему перечисление[FlagsAttribute]
, и CLR не имеет ограничений на основе атрибутов. Это было бы в идеальном мире - или был бы другой способ ограничить это - но в этом случае это просто не работает :(Я бы использовал NotSupportedException, как вы говорите. Другие перечисления, кроме определенных, не поддерживаются . Это, конечно, будет более четко указано в сообщении об исключении.
источник
Я бы пошел с
NotSupportedException
. ХотяArgumentException
выглядит хорошо, это действительно ожидаемо, когда аргумент, переданный методу, неприемлем. Аргумент типа - это определяющая характеристика фактического метода, который вы хотите вызвать, а не реальный «аргумент».InvalidOperationException
должен быть выдан, когда выполняемая вами операция может быть допустимой в некоторых случаях, но для конкретной ситуации это неприемлемо.NotSupportedException
выбрасывается, когда операция изначально не поддерживается. Например, при реализации интерфейса, в котором конкретный член не имеет смысла для класса. Это похоже на похожую ситуацию.источник
Судя по всему, Microsoft использует
ArgumentException
для этого, как показано на примере Expression.Lambda <> , Enum.TryParse <> или Marshal.GetDelegateForFunctionPointer <> в разделе «Исключения». Я не смог найти ни одного примера, указывающего на иное (несмотря на поиск в местном справочном источнике дляTDelegate
иTEnum
).Итак, я думаю, что можно с уверенностью предположить, что, по крайней мере, в коде Microsoft это обычная практика для использования
ArgumentException
недопустимых аргументов универсального типа, помимо основных переменных. Учитывая, что описание исключения в документах не делает различий между ними, это тоже не слишком большая натяжка.Надеюсь, это решит вопрос раз и навсегда.
источник
TypeArgumentException
из негоArgumentException
просто потому, что аргумент типа не является обычным аргумент.Я бы пошел с NotSupportedExpcetion.
источник
Выбрасывание индивидуализированного исключения всегда должно выполняться в любом случае, когда это вызывает сомнения. Пользовательское исключение будет работать всегда, независимо от потребностей пользователей API. Разработчик может поймать любой тип исключения, если ему все равно, но если разработчику требуется особая обработка, он будет SOL.
источник
Как насчет наследования NotSupportedException. Хотя я согласен с @Mehrdad в том, что это имеет наибольший смысл, я слышал вашу точку зрения, что это, похоже, не идеально подходит. Поэтому наследуйте NotSupportedException, и таким образом люди, кодирующие ваш API, все равно могут перехватить NotSupportedException.
источник
Я всегда с осторожностью отношусь к написанию пользовательских исключений исключительно на том основании, что они не всегда четко документируются и вызывают путаницу, если не названы правильно.
В этом случае я бы выбросил исключение ArgumentException при ошибке проверки флагов. На самом деле все зависит от предпочтений. Некоторые стандарты кодирования, которые я видел, доходят до того, что определяют, какие типы исключений следует создавать в подобных сценариях.
Если пользователь пытался передать что-то, что не было перечислением, я бы выбросил InvalidOperationException.
Редактировать:
Остальные поднимают интересный вопрос, что это не поддерживается. Меня беспокоит только NotSupportedException, что обычно это исключения, которые возникают, когда в систему вводится «темная материя», или, другими словами, «Этот метод должен входить в систему через этот интерфейс, но мы выиграли не включаю до версии 2.4 "
Я также видел, как NotSupportedExceptions генерировалось как исключение лицензирования: «вы используете бесплатную версию этого программного обеспечения, эта функция не поддерживается».
Изменить 2:
Другой возможный:
Исключение, возникающее при использовании недопустимых аргументов, которые являются перечислителями.
источник
LicensingException
класса, унаследованного отInvalidOperationException
.Я бы также проголосовал за InvalidOperationException. Я сделал (неполную) блок-схему руководств по выбрасыванию исключений .NET, основанных на рекомендациях по дизайну фреймворка 2-е изд. некоторое время назад, если кому-то интересно.
источник