MS考试70-536 - 如何从线程中抛出和处理异常?

时间:2010-03-17 16:09:47

标签: .net multithreading exception-handling

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 个答案:

答案 0 :(得分:7)

Main方法中的异常处理程序运行在与抛出异常不同的线程中。因此,thread中的异常无法在Main中捕获。检查here,了解您不希望跨线程抛出/捕获异常的原因。你应该做的是使用一个对象,它将包装你的线程逻辑但支持异常。 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;
        }
    }
}

答案 1 :(得分:3)

首先在调试模式下启动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可以为null,这是String的有效值,如果o不是字符串,则代码将抛出异常。你的意思是:

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

答案 2 :(得分:1)

异常不会遍历线程,它只是关闭执行代码。换句话说,您永远不会捕获在单独线程上抛出的异常。

答案 3 :(得分:1)

后台线程上的未处理异常将终止您的应用程序。这是.NET 2.0中的行为变化。如果您不希望应用程序在发生这种情况时死亡,则应将代码包装在try catch中并记录该异常:

private static void SomeWork(Object o)
{
    try
    {
        // execution here
    }
    catch (Exception ex)
    {
        Logger.Log(ex);
    }
}

答案 4 :(得分:0)

您是否考虑过使用BeginInvoke和EndInvoke而不是创建自己的Thread?这将允许捕获异常并将其带回调用方法。

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");
        }
    }
}