Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/286.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#_Asynchronous_Exception Handling_Async Await_Producer Consumer - Fatal编程技术网

C# 是否可以在不等待任务的情况下异步捕获异常?

C# 是否可以在不等待任务的情况下异步捕获异常?,c#,asynchronous,exception-handling,async-await,producer-consumer,C#,Asynchronous,Exception Handling,Async Await,Producer Consumer,我有一个低级CAN设备类,我想为它创建一个onMessageReceive事件。我有几个高级设备类可以使用这个CAN类的实例。我想将高级设备类的消息解析器附加到低级CAN设备onMessageReceive事件。这样,当低级类接收到数据包时,它被低级读取器任务解析为高级类。在代码中,它将如下所示 void Main() { try { using (HighLevelDevice highLevelDevice = new High

我有一个低级CAN设备类,我想为它创建一个onMessageReceive事件。我有几个高级设备类可以使用这个CAN类的实例。我想将高级设备类的消息解析器附加到低级CAN设备onMessageReceive事件。这样,当低级类接收到数据包时,它被低级读取器任务解析为高级类。在代码中,它将如下所示

void Main()
    {
        try
        {
            using (HighLevelDevice highLevelDevice = new HighLevelDevice())
            {
                while (true)
                {
                    // Use the properties/fields in highLevelDevice to make testing decisions.
                }
            }
        }
        catch (Exception)
        {
            // If the low level CAN reader task encounters an error I would like for it to asynchronously propogate up to here.
            throw;
        }
    }


    public class HighLevelDevice
    {
        private LowLevelCan lowLevelCanInstance;

        public HighLevelDevice()
        {
            lowLevelCanInstance = new LowLevelCan(this.ProcessPacket);
        }

        private void ProcessPacket(Packet packet)
        {
            // Convert packet contents into high level device properties/fields.
        }
    }

    public class LowLevelCan
    {
        private delegate void ProcessPacketDelegate(Packet packet);

        private ProcessPacketDelegate processPacket;

        private Task readerTask;

        public LowLevelCan(Action<Packet> processPacketFunction)
        {
            processPacket = new ProcessPacketDelegate(processPacketFunction);
            readerTask = Task.Run(() => readerMethod());
        }

        private async Task readerMethod()
        {
            while(notCancelled) // This would be a cancellation token, but I left that out for simplicity.
            {
                processPacket(await Task.Run(() => getNextPacket()));
            }
        }

        private Packet getNextPacket()
        {
            // Wait for next packet and then return it.
            return new Packet();
        }
    }

    public class Packet
    {
        // Data packet fields would go here.
    }
void Main()
{
尝试
{
使用(HighLevelDevice HighLevelDevice=新的HighLevelDevice())
{
while(true)
{
//使用highLevelDevice中的属性/字段做出测试决策。
}
}
}
捕获(例外)
{
//如果低级CAN读取器任务遇到错误,我希望它异步传播到这里。
投
}
}
公共级高级设备
{
私人低层can低层instance;
公共高级设备()
{
lowLevelCanInstance=新的LowLevelCan(this.ProcessPacket);
}
专用无效处理数据包(数据包)
{
//将数据包内容转换为高级设备属性/字段。
}
}
公营低阶层人士
{
私有委托void ProcessPacketDelegate(数据包);
私有ProcessPacketDelegate processPacket;
私人任务阅读任务;
公共低层CAN(操作processPacketFunction)
{
processPacket=新的ProcessPacketDelegate(processPacketFunction);
readerTask=Task.Run(()=>readerMethod());
}
专用异步任务读取器方法()
{
while(notCancelled)//这将是一个取消令牌,但为了简单起见,我省略了它。
{
processPacket(wait Task.Run(()=>getNextPacket());
}
}
私有数据包getNextPacket()
{
//等待下一个数据包,然后返回。
返回新包();
}
}
公共类数据包
{
//数据包字段将放在这里。
}
如果在GetNextPackage中抛出异常,我希望在main中捕获该异常。这有可能吗?如果我偏离了基准,完全误解了异步,我道歉。如果这样的事情是可能的,我如何改变我的方法来实现它?我可以定期检查阅读器的状态,但如果可能的话,我希望避免这种情况

此实现将杀死读卡器,但highLevelDevice线程将继续不知不觉地执行。如果我存储了错误并偶尔在主线程上检查状态,这就可以了。如果可能的话,我只想找到一个避免这种情况的解决方案


我尝试了在highLevelDevice退出的线程上创建的各种错误报告事件和进度报告。这些没有按预期工作/或者我不理解它们正在正确地做什么

没有。我已经测试过了,您必须等待任务完成才能抛出异常。等待任务或使用Task.Wait()等待任务完成

我尝试使用此代码,但未捕获异常

        try
        {
            var task = Task.Run(() => WaitASecond());

            task.ContinueWith(failedTask => throw failedTask.Exception, TaskContinuationOptions.OnlyOnFaulted);
        }
        catch (Exception ex)
        {
            throw;
        }
当我在
var task=task.Run(()=>WaitASecond())下添加
task.Wait()
它捕获了一个聚合异常并将其抛出


您必须等待所有任务完成,才能捕获异常并将其抛出Main()。

当您希望异步启动一个方法并稍后与之同步以获得结果时,标题问题适用。但是,您的问题主体所描述的实际上是对共享状态(高级设备)的并发访问。状态是从
Main
线程读取的,但由低级设备在后台线程上写入

解决方案是在高级设备中创建
Error
属性,该属性可用于跨两个线程协调错误处理:

  • 捕获低级设备引发的任何异常,并将它们传播到高级设备(请参见下文),高级设备将在属性
    error
    中存储错误
  • 将HL设备的所有读取封装在属性中,以便在读取时可以检查
    错误
    。如果发生错误,则抛出包含详细信息的异常(将在
    Main
    中捕获并处理)
净影响是来自低级设备的异常已传播到
Main

作为旁注,您的问题暗示了基于任务的异步模式,但您的低级设备实际上是以基于事件的方式编写的。看

每个模式都有传播错误的特定方法:

  • 对于基于事件的模式(EAP),您可以通过引发的任何事件的事件参数传播错误。看
  • 对于基于任务的模式(点击),当
    等待
    任务
您的
Task.Run
实际上只会将低级设备循环放在与
Main
不同的线程上,您不能等待
readerTask
,因为它代表整个处理循环,而不是单个数据包更新。而是通过事件通知各个数据包更新

总之,当低级设备捕获到异常时,它应该引发一个事件并在事件的事件参数中传递异常的详细信息。高级设备将接收事件并将详细信息存储在其
Error
属性中。这一切都发生在你的后台线程上。在主线程上,当在