我从一个非常挑剔的人那里听说,一个线程中抛出(而不是被捕获)的异常正在传播到父线程。真的吗? 我尝试过这样的东西,但是在创建线程中无法捕获异常。
static void Main(string[] args)
{
ParameterizedThreadStart pts =
new ParameterizedThreadStart(ThreadMethod);
try
{
Thread t = new Thread(pts);
t.Start(new object());
Console.ReadLine();
}
catch (Exception ex) //the exception is not caught
{
Debugger.Break();
}
}
static void ThreadMethod(object @object)
{
Thread.Sleep(2000);
throw new IndexOutOfRangeException();
Thread.CurrentThread.Abort();
}
答案 0 :(得分:12)
线程的异常不会传播到主线程的上下文。这确实有意义 - 在抛出异常时,主线程通常与包含异常处理程序的范围完全不同。
您可以通过挂钩AppDomain.UnhandledException来捕获这些异常(通常是记录它们)。有关详细信息,请参阅该页面,包括Windows窗体应用程序中的差异等。
答案 1 :(得分:2)
答案 2 :(得分:1)
不,它不会。为了捕获线程异常,您需要使用Application.ThreadException。
答案 3 :(得分:1)
C#中的线程资源,包含异常处理部分:Threading in C#
答案 4 :(得分:1)
异常在调用堆栈中向上传播。
如果从某个方法启动一个新线程,它将向上传播,直到达到该方法。
如果该方法没有捕获它,您将收到一个运行时错误,表明存在未捕获的异常。
答案 5 :(得分:1)
这是一种捕捉它并以安全的方式处理它的方法:
BackgroundWorker bg = new BackgroundWorker();
object o;
bg.DoWork += (c1,c2) =>
{
Thread.Sleep(2000);
throw new IndexOutOfRangeException();
};
bg.RunWorkerCompleted += (c3,c4) =>
{
if (((RunWorkerCompletedEventArgs)e).Error != null)
{
MessageBox.Show(((RunWorkerCompletedEventArgs)e).Error.Message);
}
};
答案 6 :(得分:1)
简而言之,不是。你有几个明显的选择:#
答案 7 :(得分:1)
异常只能在来自的线程上捕获。因此,在另一个线程上抛出异常不会导致另一个线程捕获它。
没有“父”线程的概念。
答案 8 :(得分:0)
We can use CustomExceptionHandler for this. Below code might help you.
using System;
using System.Threading;
using System.Windows.Forms;
// Create a form with a button that, when clicked, throws an exception.
public class ErrorForm : System.Windows`enter code here`.Forms.Form
{
internal Button button1;
public ErrorForm() : base()
{
// Add the button to the form.
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
this.button1.Location = new System.Drawing.Point(100, 43);
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.Text = "Click!";
this.Controls.Add(this.button1);
this.button1.Click += new EventHandler(this.button1_Click);
this.Text = "ThreadException";
this.ResumeLayout(false);
}
// Throw an exception when the button is clicked.
private void button1_Click(object sender, System.EventArgs e)
{
throw new ArgumentException("The parameter was invalid");
}
public static void Main()
{
// Add the event handler.
Application.ThreadException += new ThreadExceptionEventHandler(CustomExceptionHandler.OnThreadException);
// Start the example.
Application.Run(new ErrorForm());
}
}
// Create a class to handle the exception event.
internal class CustomExceptionHandler
{
// Handle the exception event
public static void OnThreadException(object sender, ThreadExceptionEventArgs t)
{
DialogResult result = ShowThreadExceptionDialog(t.Exception);
// Exit the program when the user clicks Abort.
if (result == DialogResult.Abort)
Application.Exit();
}
// Create and display the error message.
private static DialogResult ShowThreadExceptionDialog(Exception e)
{
string errorMsg = "An error occurred. Please contact the adminstrator " +
"with the following information:\n\n";
errorMsg += String.Format("Exception Type: {0}\n\n", e.GetType().Name);
errorMsg += "\n\nStack Trace:\n" + e.StackTrace;
return MessageBox.Show(errorMsg, "Application Error",
MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Stop);
}
}
2nd approach:-
using System;
using System.IO;
using System.Threading.Tasks;
class Example
{
static async Task Main(string[] args)
{
// Get a folder path whose directories should throw an UnauthorizedAccessException.
string path = Directory.GetParent(
Environment.GetFolderPath(
Environment.SpecialFolder.UserProfile)).FullName;
// Use this line to throw UnauthorizedAccessException, which we handle.
Task<string[]> task1 = Task<string[]>.Factory.StartNew(() => GetAllFiles(path));
// Use this line to throw an exception that is not handled.
// Task task1 = Task.Factory.StartNew(() => { throw new IndexOutOfRangeException(); } );
try {
await task1;
}
catch (AggregateException ae) {
ae.Handle((x) =>
{
if (x is UnauthorizedAccessException) // This we know how to handle.
{
Console.WriteLine("You do not have permission to access all folders in this path.");
Console.WriteLine("See your network administrator or try another path.");
return true;
}
return false; // Let anything else stop the application.
});
}
Console.WriteLine("task1 Status: {0}{1}", task1.IsCompleted ? "Completed," : "",
task1.Status);
}
static string[] GetAllFiles(string str)
{
// Should throw an UnauthorizedAccessException exception.
return System.IO.Directory.GetFiles(str, "*.txt", System.IO.SearchOption.AllDirectories);
}
}