C# 停止异步lambda向上传播调用堆栈的异常

C# 停止异步lambda向上传播调用堆栈的异常,c#,exception,async-await,C#,Exception,Async Await,下面的代码有一个TaskMonitor类,它是Stephen Cleary的修改版本。Worker类使用TaskMonitor类异步运行Worker.CheckStatus Worker.CheckStatus通常会引发异常(例如数据库连接问题)。我希望TaskMonitor.Monitor阻止该异常到达Program.Main,并通过Exception和InnerException属性公开它。TaskMonitor.Monitor中的catch块被命中,但未按预期吞下异常;异常被传递到Prog

下面的代码有一个TaskMonitor类,它是Stephen Cleary的修改版本。Worker类使用TaskMonitor类异步运行Worker.CheckStatus

Worker.CheckStatus通常会引发异常(例如数据库连接问题)。我希望TaskMonitor.Monitor阻止该异常到达Program.Main,并通过Exception和InnerException属性公开它。TaskMonitor.Monitor中的catch块被命中,但未按预期吞下异常;异常被传递到Program.Main并使应用程序崩溃。如何停止TaskMonitor.Monitor中的异常

public sealed class TaskMonitor {
    // Based on Stephen Cleary's NotifyTaskCompletion:
    // https://github.com/StephenCleary/Mvvm/blob/master/future/Nito.Mvvm.Async/NotifyTask.cs

    public TaskMonitor(Task task = null) {
        Task = task;
    }

    public AggregateException Exception {
        get {
            return Task?.Exception;
        }
    }

    public Exception InnerException {
        get {
            return Exception?.InnerException;
        }
    }

    public bool IsCompleted {
        get {
            return Task != null && Task.IsCompleted;
        }
    }

    public bool IsRunning {
        get {
            return Task != null && !Task.IsCompleted;
        }
    }

    private async Task Monitor(Task task) {
        try {
            if(task != null) {
                await task;
            }
        }
        catch {
            // Drop exceptions
        }
        finally {
            // do other stuff here like raise PropertyChanged
        }
    }

    private Task _task;

    public Task Task {
        get => _task;
        set {
            if(Task != value) {
                _task = value;
                _ = Monitor(Task);
            }
        }
    }
}

public class Worker {
    public Worker() {
        CheckStatusMonitor = new TaskMonitor();
    }

    public void CheckStatus() {
        if(!CheckStatusMonitor.IsRunning) {
            CheckStatusMonitor.Task = Task.Run(async () => {
                var newStatus = WorkerStatus.Unknown;
                try {
                    // Force a database connection failure
                    var cn = new SqlConnection();
                    await cn.OpenAsync();

                    newStatus = WorkerStatus.Good;
                }
                catch(Exception ex) {
                    newStatus = WorkerStatus.Error;
                    throw ex;
                }
                finally {
                    Status = newStatus;
                }
            });
        }
    }

    public TaskMonitor CheckStatusMonitor { get; private set; }

    public WorkerStatus Status { get; private set; }
}

public enum WorkerStatus {
    Unknown,
    Error,
    Good,
}

class Program {
    public static async Task Main() {
        var worker = new Worker();
        worker.CheckStatus();
        await worker.CheckStatusMonitor.Task;
        Debug.WriteLine(worker.CheckStatusMonitor.ErrorMessage);
    }
}
TaskMonitor.Monitor中的catch块被命中,但未按预期吞下异常;异常被传递到Program.Main并使应用程序崩溃。如何停止TaskMonitor.Monitor中的异常

public sealed class TaskMonitor {
    // Based on Stephen Cleary's NotifyTaskCompletion:
    // https://github.com/StephenCleary/Mvvm/blob/master/future/Nito.Mvvm.Async/NotifyTask.cs

    public TaskMonitor(Task task = null) {
        Task = task;
    }

    public AggregateException Exception {
        get {
            return Task?.Exception;
        }
    }

    public Exception InnerException {
        get {
            return Exception?.InnerException;
        }
    }

    public bool IsCompleted {
        get {
            return Task != null && Task.IsCompleted;
        }
    }

    public bool IsRunning {
        get {
            return Task != null && !Task.IsCompleted;
        }
    }

    private async Task Monitor(Task task) {
        try {
            if(task != null) {
                await task;
            }
        }
        catch {
            // Drop exceptions
        }
        finally {
            // do other stuff here like raise PropertyChanged
        }
    }

    private Task _task;

    public Task Task {
        get => _task;
        set {
            if(Task != value) {
                _task = value;
                _ = Monitor(Task);
            }
        }
    }
}

public class Worker {
    public Worker() {
        CheckStatusMonitor = new TaskMonitor();
    }

    public void CheckStatus() {
        if(!CheckStatusMonitor.IsRunning) {
            CheckStatusMonitor.Task = Task.Run(async () => {
                var newStatus = WorkerStatus.Unknown;
                try {
                    // Force a database connection failure
                    var cn = new SqlConnection();
                    await cn.OpenAsync();

                    newStatus = WorkerStatus.Good;
                }
                catch(Exception ex) {
                    newStatus = WorkerStatus.Error;
                    throw ex;
                }
                finally {
                    Status = newStatus;
                }
            });
        }
    }

    public TaskMonitor CheckStatusMonitor { get; private set; }

    public WorkerStatus Status { get; private set; }
}

public enum WorkerStatus {
    Unknown,
    Error,
    Good,
}

class Program {
    public static async Task Main() {
        var worker = new Worker();
        worker.CheckStatus();
        await worker.CheckStatusMonitor.Task;
        Debug.WriteLine(worker.CheckStatusMonitor.ErrorMessage);
    }
}
Main
中,您的代码正在执行
wait worker.CheckStatusMonitor.Task
TaskMonitor返回的任务。任务
任务。从
工作者运行
任务。检查状态
,而不是从
TaskMonitor.Monitor
返回的任务

如果要忽略异常,则需要等待正确的任务:

public Task Task {
  get => _task;
  set {
    _task = Monitor(value);
  }
}
请注意,
if(Task!=value)
已被删除,因为这显然不起作用,因为任务正在被替换

TaskMonitor.Monitor中的catch块被命中,但未按预期吞下异常;异常被传递到Program.Main并使应用程序崩溃。如何停止TaskMonitor.Monitor中的异常

public sealed class TaskMonitor {
    // Based on Stephen Cleary's NotifyTaskCompletion:
    // https://github.com/StephenCleary/Mvvm/blob/master/future/Nito.Mvvm.Async/NotifyTask.cs

    public TaskMonitor(Task task = null) {
        Task = task;
    }

    public AggregateException Exception {
        get {
            return Task?.Exception;
        }
    }

    public Exception InnerException {
        get {
            return Exception?.InnerException;
        }
    }

    public bool IsCompleted {
        get {
            return Task != null && Task.IsCompleted;
        }
    }

    public bool IsRunning {
        get {
            return Task != null && !Task.IsCompleted;
        }
    }

    private async Task Monitor(Task task) {
        try {
            if(task != null) {
                await task;
            }
        }
        catch {
            // Drop exceptions
        }
        finally {
            // do other stuff here like raise PropertyChanged
        }
    }

    private Task _task;

    public Task Task {
        get => _task;
        set {
            if(Task != value) {
                _task = value;
                _ = Monitor(Task);
            }
        }
    }
}

public class Worker {
    public Worker() {
        CheckStatusMonitor = new TaskMonitor();
    }

    public void CheckStatus() {
        if(!CheckStatusMonitor.IsRunning) {
            CheckStatusMonitor.Task = Task.Run(async () => {
                var newStatus = WorkerStatus.Unknown;
                try {
                    // Force a database connection failure
                    var cn = new SqlConnection();
                    await cn.OpenAsync();

                    newStatus = WorkerStatus.Good;
                }
                catch(Exception ex) {
                    newStatus = WorkerStatus.Error;
                    throw ex;
                }
                finally {
                    Status = newStatus;
                }
            });
        }
    }

    public TaskMonitor CheckStatusMonitor { get; private set; }

    public WorkerStatus Status { get; private set; }
}

public enum WorkerStatus {
    Unknown,
    Error,
    Good,
}

class Program {
    public static async Task Main() {
        var worker = new Worker();
        worker.CheckStatus();
        await worker.CheckStatusMonitor.Task;
        Debug.WriteLine(worker.CheckStatusMonitor.ErrorMessage);
    }
}
Main
中,您的代码正在执行
wait worker.CheckStatusMonitor.Task
TaskMonitor返回的任务。任务
任务。从
工作者运行
任务。检查状态
,而不是从
TaskMonitor.Monitor
返回的任务

如果要忽略异常,则需要等待正确的任务:

public Task Task {
  get => _task;
  set {
    _task = Monitor(value);
  }
}

请注意,如果(Task!=value)
被删除,因为这显然不起作用,因为任务正在被替换。

您将
\u Task
设置为从
任务返回的
任务。运行
,而不是从
监视器返回的
任务。然后在
await worker.CheckStatusMonitor.Task中等待
您将
\u任务
设置为从
任务返回的
任务
。运行
,而不是从
监视器
返回的
任务
。然后在
await worker.CheckStatusMonitor.Task中等待我非常确定CheckStatus中的Task.Run调用以某种方式作为异步void运行,因此我忽略了代码正在等待错误的任务。为了解决这个问题,我添加了TaskMonitor.MonitorTask属性(比如NotifyTask.TaskCompleted),并修改了其他TaskMonitor属性以引用相应的任务。谢谢你的帮助!我非常确定CheckStatus中的Task.Run调用以某种方式作为异步void运行,因此我忽略了代码正在等待错误的任务。为了解决这个问题,我添加了TaskMonitor.MonitorTask属性(比如NotifyTask.TaskCompleted),并修改了其他TaskMonitor属性以引用相应的任务。谢谢你的帮助!