Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 捕获在不同线程中引发的异常_C#_Multithreading_Exception Handling - Fatal编程技术网

C# 捕获在不同线程中引发的异常

C# 捕获在不同线程中引发的异常,c#,multithreading,exception-handling,C#,Multithreading,Exception Handling,我的一个方法(Method1)生成一个新线程。 该线程执行一个方法(Method2),在执行过程中引发异常。 我需要获取调用方法(Method1)的异常信息 是否有某种方法可以在Method1中捕获在Method2中抛出的异常?您无法在Method1中捕获异常。但是,您可以在Method2中捕获异常并将其记录到一个变量中,然后原始执行线程可以读取并使用该变量。在.NET 4及更高版本中,您可以使用任务类而不是创建新线程。然后可以使用任务对象上的.exceptions属性获取异常。 有两种方法可以

我的一个方法(
Method1
)生成一个新线程。 该线程执行一个方法(
Method2
),在执行过程中引发异常。 我需要获取调用方法(
Method1
)的异常信息


是否有某种方法可以在
Method1
中捕获在
Method2
中抛出的异常?

您无法在Method1中捕获异常。但是,您可以在Method2中捕获异常并将其记录到一个变量中,然后原始执行线程可以读取并使用该变量。

.NET 4及更高版本中,您可以使用
任务
类而不是创建新线程。然后可以使用任务对象上的
.exceptions
属性获取异常。 有两种方法可以做到这一点:

  • 在一个单独的方法中://您在一些任务的线程中处理异常

    class Program
    {
        static void Main(string[] args)
        {
            Task<int> task = new Task<int>(Test);
            task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
            task.Start();
            Console.ReadLine();
        }
    
        static int Test()
        {
            throw new Exception();
        }
    
        static void ExceptionHandler(Task<int> task)
        {
            var exception = task.Exception;
            Console.WriteLine(exception);
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Task<int> task = new Task<int>(Test);
            task.Start();
    
            try
            {
                task.Wait();
            }
            catch (AggregateException ex)
            {
                Console.WriteLine(ex);    
            }
    
            Console.ReadLine();
        }
    
        static int Test()
        {
            throw new Exception();
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Exception exception = null;
            Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), Handler));
            thread.Start();            
    
            Console.ReadLine();
        }
    
        private static void Handler(Exception exception)
        {        
            Console.WriteLine(exception);
        }
    
        private static void SafeExecute(Action test, Action<Exception> handler)
        {
            try
            {
                test.Invoke();
            }
            catch (Exception ex)
            {
                Handler(ex);
            }
        }
    
        static void Test(int a, int b)
        {
            throw new Exception();
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Exception exception = null;
            Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), out exception));
    
            thread.Start();            
    
            thread.Join();
    
            Console.WriteLine(exception);    
    
            Console.ReadLine();
        }
    
        private static void SafeExecute(Action test, out Exception exception)
        {
            exception = null;
    
            try
            {
                test.Invoke();
            }
            catch (Exception ex)
            {
                exception = ex;
            }
        }
    
        static void Test(int a, int b)
        {
            throw new Exception();
        }
    }
    
  • 或者//在调用方的线程中处理异常

    class Program
    {
        static void Main(string[] args)
        {
            Task<int> task = new Task<int>(Test);
            task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
            task.Start();
            Console.ReadLine();
        }
    
        static int Test()
        {
            throw new Exception();
        }
    
        static void ExceptionHandler(Task<int> task)
        {
            var exception = task.Exception;
            Console.WriteLine(exception);
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Task<int> task = new Task<int>(Test);
            task.Start();
    
            try
            {
                task.Wait();
            }
            catch (AggregateException ex)
            {
                Console.WriteLine(ex);    
            }
    
            Console.ReadLine();
        }
    
        static int Test()
        {
            throw new Exception();
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Exception exception = null;
            Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), Handler));
            thread.Start();            
    
            Console.ReadLine();
        }
    
        private static void Handler(Exception exception)
        {        
            Console.WriteLine(exception);
        }
    
        private static void SafeExecute(Action test, Action<Exception> handler)
        {
            try
            {
                test.Invoke();
            }
            catch (Exception ex)
            {
                Handler(ex);
            }
        }
    
        static void Test(int a, int b)
        {
            throw new Exception();
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Exception exception = null;
            Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), out exception));
    
            thread.Start();            
    
            thread.Join();
    
            Console.WriteLine(exception);    
    
            Console.ReadLine();
        }
    
        private static void SafeExecute(Action test, out Exception exception)
        {
            exception = null;
    
            try
            {
                test.Invoke();
            }
            catch (Exception ex)
            {
                exception = ex;
            }
        }
    
        static void Test(int a, int b)
        {
            throw new Exception();
        }
    }
    

  • 在不同线程之间共享数据的最简单方法是
    共享数据
    ,如下所示(有些是伪代码):

    你可以在中读到这个方法,但是,我更喜欢在Albahari兄弟(2007)的《O'Reilly C#3.0简而言之》(C#3.0)一书中读到这个方法,这本书也可以在Google Books上免费访问,就像这本书的更新版本一样,因为它还包括线程池、前台线程与后台线程等,使用漂亮简单的示例代码。(免责声明:我拥有本书的一份旧版)


    如果您正在制作WinForms应用程序,使用共享数据尤其方便,因为WinForm控件不是线程安全的。使用回调将数据从工作线程传递回WinForm控件,主UI线程需要使用
    Invoke()
    编写丑陋的代码,以使该控件线程安全。相反,使用共享数据和单线程
    System.Windows.Forms.Timer
    ,间隔时间短,比如说0.2秒,您可以轻松地将信息从工作线程发送到控件,而无需调用
    Invoke

    我有一个特别的问题,我想使用包含控件的项,来自集成测试套件,因此必须创建STA线程。我最后得到的代码如下,放在这里,以防其他人也有同样的问题

        public Boolean? Dance(String name) {
    
            // Already on an STA thread, so just go for it
            if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) return DanceSTA(name);
    
            // Local variable to hold the caught exception until the caller can rethrow
            Exception lException = null;
    
            Boolean? lResult = null;
    
            // A gate to hold the calling thread until the called thread is done
            var lGate = new ManualResetEvent(false);
    
            var lThreadStart = new ThreadStart(() => {
                try {
                    lResult = DanceSTA(name);
                } catch (Exception ex) {
                    lException = ex;
                }
                lGate.Set();
            });
    
            var lThread = new Thread(lThreadStart);
            lThread.SetApartmentState(ApartmentState.STA);
            lThread.Start();
    
            lGate.WaitOne();
    
            if (lException != null) throw lException;
    
            return lResult;
        }
    
        public Boolean? DanceSTA(String name) { ... }
    

    这是代码的直接粘贴。对于其他用途,我建议提供一个动作或函数作为参数,并在线程上调用它,而不是硬编码被调用的方法。

    感谢您的回复。所以如果Method1是Class1的一部分,并且我在该类中有一个Exception类型的变量。每当Method2抛出异常时,它也会在Class1中设置该异常变量。这听起来像是一个公平的设计吗?是否有处理此场景的最佳实践方法?正确,您只需存储异常并稍后访问它。将来运行的方法(尤其是Method2完成时的回调)会重新引发该异常,就好像它们自己导致了该异常一样,这并不少见,但这取决于您想要什么。很抱歉,我忘了提到我使用的是.NET 3.5。根据我的理解,任务是4.0吗?@SilverlightStudent好的,我刚刚更新了我的答案以满足您的要求。@oxilumin:谢谢,非常感谢。还有一个后续问题。如果您的Test()方法也包含一些参数,那么您将如何修改这些参数的SafeExecute方法?@SilverlightStudent在这种情况下,我将传递lambda而不是
    Test
    。像
    ()=>测试(myParameter1,myParameter2)
    @SilverlightStudent:Updated。