C #: должен ли я выдавать исключение ArgumentException или NotSupportedException, когда тип аргумента не поддерживается?

#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 был поддержан и вам правильно сообщили, что попытка не удалась)