MS Exam 70-536 - Как бросить и обработать исключение из потока? - PullRequest
2 голосов
/ 17 марта 2010

В MS Exam 70-536 .Net Foundation , Глава 7 «Потоки» в Уроке 1 Создание тем есть текст:

Имейте в виду, что поскольку метод WorkWithParameter принимает объект, Thread.Start может вызываться с любым объектом вместо ожидаемой строки. Быть осторожным в выборе Ваш метод запуска потока для работы с неизвестными типами имеет решающее значение для хорошего многопоточный код. Вместо слепого приведения параметра метода в нашу строку, это Рекомендуется проверить тип объекта, как показано в следующем примере:

' VB
Dim info As String = o as String
If info Is Nothing Then
    Throw InvalidProgramException("Parameter for thread must be a string")
End If
// C#
string info = o as string;
if (info == null)
{
    throw InvalidProgramException("Parameter for thread must be a string");
} 

Итак, я пробовал это, но исключение не обрабатывается должным образом (нет записи об исключении консоли, программа завершается), что не так с моим кодом (ниже)?

class Program
    {
        static void Main(string[] args)
        {
            Thread thread = new Thread(SomeWork);
            try
            {
                thread.Start(null);
                thread.Join();
            }
            catch (InvalidProgramException ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {

                Console.ReadKey();
            }
        }

        private static void SomeWork(Object o)
        {
            String value = (String)o;
            if (value == null)
            {
                throw new InvalidProgramException("Parameter for "+
                    "thread must be a string");
            }
        }
    }

Спасибо за ваше время!

Ответы [ 5 ]

7 голосов
/ 17 марта 2010

Обработчик исключения в вашем методе Main работает в потоке, отличном от создаваемого исключения. Таким образом, исключение в thread не может быть поймано в Main. Проверьте здесь для обсуждения того, почему вы не хотите бросать / перехватывать исключения в потоках. Вместо этого вам следует использовать объект, который обернет логику вашего потока, но будет поддерживать исключения. E.g.:

class Program
{
    static void Main(string[] args)
    {
        ExceptionHandlingThreadWrapper wrapper = new ExceptionHandlingThreadWrapper();
        Thread thread = new Thread(wrapper.Run);
        try
        {
            thread.Start(null);
            thread.Join();
            if (wrapper.Exception != null)
                throw new Exception("Caught exception", wrapper.Exception);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
        finally { Console.ReadKey(); }
    }
}

public class ExceptionHandlingThreadWrapper
{
    public ExceptionHandlingThreadWrapper()
    {
        this.Exception = null;
    }

    public Exception Exception { get; set; }

    public void Run(Object obj)
    {
        try
        {
            String value = obj as String;
            if (value == null)
                throw new Exception("Argument must be string");
        }
        catch (Exception ex)
        {
            this.Exception = ex;
        }
    }
}
3 голосов
/ 17 марта 2010

Первый запуск в VS в режиме отладки. Теперь закодируем несколько вопросов:

    catch (InvalidProgramException ex)
    {
        Console.WriteLine(ex.Message);
    }

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

throw new InvalidProgramException("Parameter for "+
                    "thread must be a string");

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

    String value = (String)o;
    if (value == null)

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

    String value = o as String;
    if (value == null)
1 голос
/ 17 марта 2010

Необработанное исключение в фоновом потоке прекратит работу вашего приложения.Это поведенческое изменение в .NET 2.0.Если вы не хотите, чтобы ваше приложение умерло, когда это произойдет, вам следует поместить код в try catch и записать это исключение:

private static void SomeWork(Object o)
{
    try
    {
        // execution here
    }
    catch (Exception ex)
    {
        Logger.Log(ex);
    }
}
1 голос
/ 17 марта 2010

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

0 голосов
/ 17 марта 2010

Рассматривали ли вы использование BeginInvoke и EndInvoke вместо создания собственного потока? Это позволит перехватить исключение и вернуть его в вызывающий метод.

class Program
{
    private delegate void WorkDelegate(Object o);

    static void Main(string[] args)
    {
        WorkDelegate workDel = new WorkDelegate(SomeWork);
        // first argument is passing a null object that will throw 
        // the exception in the SomeWork method
        IAsyncResult result = workDel.BeginInvoke(null, null, null);
        try
        {
            workDel.EndInvoke(result);
        }
        catch (InvalidProgramException ex)
        {
            Console.WriteLine(ex.Message);
        }
        finally
        {
            Console.ReadKey();
        }
    }

    private static void SomeWork(Object o)
    {
        String value = o as String;
        if (value == null)
        {
            throw new InvalidProgramException("Parameter for "+
                "thread must be a string");
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...