#c# #polymorphism #custom-exceptions #argumentexception #notsupportedexception
#c# #полиморфизм #пользовательские исключения #исключение argumentexception #исключение notsupportedexception
Вопрос:
Итак, у меня ситуация, когда мне нужно выдать исключение, потому что «аргумент не поддерживается». Чтобы объяснить, как я сюда попал, приведу примерную ситуацию:
- Оки бывают многих видов, включая Вкусняшки и Закутки
- Оукс может дружить с другими Оукс, но только с правильными типами
- Юки могут дружить с Зуками, но Зуки не могут дружить с Юками
Пример кода:
public abstract class Ook
{
public abstract bool TryBefriendYook(Yook yook);
public abstract bool TryBefriendZook(Zook zook);
public bool TryBefriend(Ook o0k)
{
Type ookType = ook.GetType;
if (ookType == typeof(Yook))
{
TryBefriendYook((Yook)ook);
return true;
}
else if (ookType == typeof(Zook))
{
TryBefriendZook((Zook)ook);
return true;
}
else return false;
}
public void Befriend(Ook ook)
{
if(!TryBefriend(ook))
throw new Exception(
"argument type not supported");
}
}
public sealed class Yook : Ook
{
public override bool TryBefriendYook(Yook yook)
{
return true;
}
public override bool TryBefriendZook(Zook zook)
{
return true;
}
}
public partial sealed class Zook : Ook
{
public override bool TryBefriendYook(Yook yook)
{
return false;
}
public override bool TryBefriendZook(Zook zook)
{
return true;
}
}
Итак, этот тип подпадает под оба ArgumentException
(аргумент не подходит для подкласса) и NotSupportedException
(подкласс не принимает аргумент), не так ли?
Итак, какой из них мне следует выбрать — или вместо этого мне следует написать пользовательское исключение для этой ситуации?
Комментарии:
1.
NotSupportedException
выдается, когда вызываемый метод не поддерживается, msdn описывает случаи.ArgumentException
или здесь больше подходит ваш собственный2. Есть ли какая-либо причина, по которой вы хотите использовать определенный тип исключения?
3. @PavelAnikhouski В этом случае
Zook.BefriendYook
не поддерживается. Это почти точно такой же вариант использования, как и первый пример, приведенный в msdn. @TheDon вы всегда должны выдавать наиболее конкретное возможное исключение и никогда не выдавать простоеSystem.Exception
.
Ответ №1:
Вы не должны выдавать ни одно исключение. Вы объявили этот метод:
public bool TryBefriend(Ook o0k)
В нем говорится, что этот метод ожидает аргумент типа Ook
. Если кто-то передает аргумент этого типа или одного из его подклассов, и он компилируется, тогда было бы нехорошо выдавать им ошибку времени выполнения и, по сути, говорить: «Нет, не тот тип. Я действительно имел в виду этот тип и этот тип, но не тот.»
Если возможно попытаться подружиться с чем-либо, но в результате это может быть успешным, а может и нет, то попытка не должна вызывать исключение. Мы не должны использовать исключения как способ управления нормальным, предсказуемым потоком программы.
Думайте об этом как о попытке вывести деньги из банка. Если вы попытаетесь вывести 1000 долларов, вы должны получить сообщение о том, что это удалось, или о том, что это не удалось, потому что у вас нет 1000 долларов. Он не должен возвращать успех, если у вас достаточно денег, или выдавать исключение, если у вас этого нет. Отсутствие достаточного количества денег — нормальная, предсказуемая возможность. Если, с другой стороны, приложение не может продолжить работу, потому что оно потеряло соединение с базой данных и нет способа восстановить, то создание исключения имело бы смысл.
Поэтому я бы просто вернул true
or false
, и тогда вызывающий может решить, что делать, на основе ответа. Вы увидите это, что имеет смысл:
if(someOok.TryBefriend(someOtherOook))
{
// friends!
}
else
{
// not friends!
}
…и не это, что неудобно:
try
{
someOok.TryBefriend(someOtherOook);
// friends!
}
catch(NotSupportedException ex)
{
// not friends!
}
Ответ №2:
Согласно MSDN:
NotSupportedException Исключение, которое выдается, когда вызванный метод не поддерживается или когда предпринимается попытка чтения, поиска или записи в поток, который не поддерживает вызванную функциональность.
Класс ArgumentException Исключение, которое выдается, когда один из аргументов, предоставленных методу, недействителен
Итак, согласно MSDN, исключение ArgumentException больше подходит для вашего случая редактировать: если абсолютно необходимо больше аргументов или пользовательский возврат, вы можете написать свое собственное пользовательское исключение, однако нет проблем в использовании исключения ArgumentException, если оно соответствует вашим потребностям.
Комментарии:
1. Проблема в том, что это также случай, когда вызываемый метод не поддерживается (т. Е.
Zook.BefriendYook
)2. @TravisReed: Вызывающий
Befriend
не вызывал неподдерживаемый метод. Ваша реализацияBefriend
сделала это. Не создавайте исключений, чтобы заставить вызывающую сторону разобраться с ошибками в вашей реализации. (Но на самом деле ваш звонок вZook.TryBefriendYook
был поддержан и вам правильно сообщили, что попытка не удалась)