【问题标题】:MS Exam 70-536 - How to throw and handle exception from thread?MS 考试 70-536 - 如何从线程中抛出和处理异常?
【发布时间】:2010-03-17 16:09:47
【问题描述】:

MS Exam 70-536 .Net Foundation,第 1 课创建线程的第 7 章“线程”中有一段文字:

请注意,因为 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");
            }
        }
    }

感谢您的宝贵时间!

【问题讨论】:

    标签: .net multithreading exception-handling


    【解决方案1】:

    Main 方法中的异常处理程序在与引发异常的线程不同的线程中运行。因此,thread 中的异常无法在 Main 中捕获。查看here,了解为什么您不想跨线程抛出/捕获异常。你应该做的是使用一个对象来包装你的线程逻辑但支持异常。例如:

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

    【讨论】:

      【解决方案2】:

      首先在 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)
      

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          【解决方案4】:

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

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

          【讨论】:

          • 谢谢,很好的建议,但我真的很想把它传递出去
          【解决方案5】:

          您是否考虑过使用 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");
                  }
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-10-11
            • 1970-01-01
            • 2014-04-03
            • 2011-11-23
            • 1970-01-01
            • 1970-01-01
            • 2014-08-07
            • 2022-11-04
            相关资源
            最近更新 更多