Вопрос о том, где позиционировать операторы Try and Catch - PullRequest
9 голосов
/ 14 февраля 2011

Я использовал операторы try и catch как простой способ сохранить мой код без сбоев (я бы все обернул).Недавно я хотел начать использовать операторы try и catch более правильно.Вот в качестве примера у меня есть вопросы о:

public class Ninja{
    Ninja(){
    }

    public void ThrowShirikin(int numberOfShirikins){
        try{
            if(numberOfShirikins == 0){
                throw new System.ArgumentException("Invalid number of shirikins");
            }

            //Throw shirikin
        }
        catch(ArgumentException e){
            MessageBox.Show(e.Message);
        }
    }
}

В вышеупомянутом классе Ninja все содержимое моего метода ThrowShirikin содержится в цикле try.Поскольку существует только одна возможность для ошибки ввода (в этом случае, когда numberOfShirikins == 0), не должны ли в цикле try содержаться только строки кода, проверяющие это?См. Ниже:

public class Ninja{
    Ninja(){
    }

    public void ThrowShirikin(int numberOfShirikins){
        bool errorsExist = false;
        try{
            if(numberOfShirikins == 0){
                errorsExist = true;
                throw new System.ArgumentException("Invalid number of shirikins");
            }
        }
        catch(ArgumentException e){
            MessageBox.Show(e.Message);
        }

        if(!errorsExist){
            //Throw shirikin
        }
    }
}

^ Но то, что я здесь имею, кажется немного неуклюжим.Любые предложения и пожелания о том, как я понимаю использование операторов try catch?Спасибо!

Редактировать:

Или я мог бы сделать что-то вроде этого, чтобы код // Throw shirikin никогда не выполнялся, если для numberOfShirikins неверное значение?

Ответы [ 9 ]

5 голосов
/ 14 февраля 2011

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

4 голосов
/ 14 февраля 2011

Похоже, что try/catch существует только для того, чтобы поймать исключение, которое вы выбираете, чтобы создать и выбросить, а затем вы поймаете его просто для того, чтобы открыть окно сообщения для пользователя.Затем вы решаете либо продолжить, либо не исходя из условия ошибки.

Ликвидация try и catch.Устранить окно сообщения. Do сгенерировать исключение для неверного аргумента.Пусть вызывающая функция определяет, хотят ли они поймать и как они хотят обработать.Ваш Ninja класс не должен принимать эти решения, кроме определения того, что является действительным, а что нет.

if (numberOfShirikins == 0)
    throw new ArgumentException("...");

// rest of your shirikin throwing code
2 голосов
/ 14 февраля 2011

Вы никогда не должны ловить исключения таким образом. Только ловить исключения, которые вы можете обработать .

public class Ninja{
    Ninja(){
    }

    public void ThrowShirikin(int numberOfShirikins){
            if(numberOfShirikins <= 0){
                throw new System.ArgumentException("Invalid number of shirikins");
            }
        //Throw shirikin
    }
}

Я предлагаю начать программирование, не используя try / catch. Затем исправьте любые исключения, которые вы видите, не скрывайте их.

1 голос
/ 14 февраля 2011

Когда вы выбрасываете исключение, вы в основном говорите: «Это исключительная ситуация, с которой я не знаю, как справиться (или другой метод более высокого уровня мог бы лучше понять, как это должно быть обработано)»

Итак, метод, который вы только что опубликовали, говорит: «Я не знаю, что делать, когда меня просят бросить 0 сюрикенов. На самом деле я солгал, я собираюсь показать окно сообщения»

Либо пропустите исключение все вместе и покажите сообщение (не идеально, но лучше, чем выбрасывание, чем то, что у вас есть), либо просто выбросьте исключение и поймайте его выше в коде интерфейса пользователя.Возможно, вы захотите создать свой собственный тип исключения, если хотите специально обработать этот конкретный тип.

1 голос
/ 14 февраля 2011

Ни одна хорошая идея.Нет смысла генерировать исключение и перехватывать его одним и тем же методом и отображать диалоговое окно форм из этого класса.

В вашем графическом интерфейсе только те классы, которые должны содержать код GUI.* В вашем случае я бы тоже не использовал исключение, я бы использовал логическое возвращаемое значение:

public bool ThrowShirikin(int numberOfShirikins){
            if(numberOfShirikins == 0){
                return false;
            }
            //throw
            return true;
    }

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

Также имейте в виду, что код errorsExist = true; вашего второго способа никогда не будет вызываться, поскольку он находится ниже инструкции throw.

1 голос
/ 14 февраля 2011

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

Кроме того, в вышеприведенном примере для ErrorExist никогда не будет установлено значение true - это должно быть помещено в ваш блок catch, а не непосредственно в то место, где вы генерируете исключение.Это завершает нормальный программный поток.

Повторно, метод будет выглядеть следующим образом.

public void ThrowShirikin(int numberOfShirikins) {
    if(numberOfShirikins == 0){
        throw new System.ArgumentException("Invalid number of shirikins", "numberOfShirikins");
    }

    //Throw shirikin
}

Это будет зависеть от класса, вызывающего метод, чтобы решить, что делать с исключением.

1 голос
/ 14 февраля 2011

Нет реальной причины перехватывать исключения одним и тем же способом.Обойтись без:

public class Ninja{
    Ninja(){
    }

    public void ThrowShirikin(int numberOfShirikins){
        if(numberOfShirikins == 0){
            MessageBox.Show(e.Message);
            return;
        }

        //...
    }
}
0 голосов
/ 15 февраля 2011

Если вы можете избежать исключения, вам следует. Они стоят около 1000-4000 тактов.

0 голосов
/ 14 февраля 2011

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

Еслифрагмент кода, который вы показали выше, имеет numberOfShirikins == 0 не исключительное условие, это обычная проверка аргументов

Итак, я бы переформулировал код следующим образом:

public class Ninja{
    Ninja(){
    }

    public void ThrowShirikin(int numberOfShirikins){
        bool errorsExist = false;
        try{
            if(numberOfShirikins == 0){ showUserMessage("Invalid number of shirikins", MessageType.Information); }
        }
        catch(ArgumentException e){
            showUserMessage(e.Message, MessageType.Exception, e);
        }

        if(!errorsExist){
            //Throw shirikin
        }
    }
   private showUserMessage(string message, MessageType type, Exception ex = null){
        MessageBox.Show(message);
   }

}

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

Теперьмой код будет выглядеть так:

public class Ninja{
        Ninja(){
        }

        public void ThrowShirikin(int numberOfShirikins){
                if(numberOfShirikins == 0){ showUserMessage("Invalid number of shirikins", MessageType.Information); return; }
                else{ /* do something here */ }
        }

С другой стороны, если numberOfShirikins == 0 является исключительным условием, я напишу пользовательское исключение с кодом в виде:

public class Ninja{
        Ninja(){
        }

        public void ThrowShirikin(int numberOfShirikins){
                if(numberOfShirikins == 0){ throw NumberOfShirikinsException(); }
                else{ /* do something here */ }
        }
...