物理模拟运行时非中断类问题与警告的处理方案咨询
物理模拟应用的三类问题解决方案
针对你提到的物理模拟应用中与UI解耦的两类问题,以下是具体实现方案:
案例3:非暂停警告的无侵入式收集方案
实现思路
使用AsyncLocal<WarningsHandler>实现上下文隔离的警告收集,既避免依赖注入对方法签名的污染,又能区分不同模拟实例的警告:
AsyncLocal绑定当前异步执行上下文,多实例并行运行时警告不会互相干扰- 核心代码通过静态访问点添加警告,无需修改构造函数或方法参数
- UI层在启动模拟前初始化警告处理器并绑定到上下文,模拟结束后直接读取警告列表
修改后代码
// 静态上下文类,提供无侵入的警告访问入口 public static class WarningContext { private static readonly AsyncLocal<WarningsHandler> _currentHandler = new(); public static WarningsHandler Current { get => _currentHandler.Value ?? throw new InvalidOperationException("警告处理器未初始化"); set => _currentHandler.Value = value; } // 简化核心代码的调用方式 public static void AddWarning(string message) => Current.Add(message); } public class WarningsHandler { public List<string> Warnings { get; init; } = new(); public void Add(string warning) => Warnings.Add(warning); } public class Ui { public void RunSimulationCommand() { var sim = new SimulationCore(); var warningsHandler = new WarningsHandler(); // 绑定当前模拟实例的警告处理器 WarningContext.Current = warningsHandler; try { sim.RunSimulation(); // 模拟结束后展示所有警告 foreach (var warning in warningsHandler.Warnings) { MessageBox.Show(warning); } } catch (Exception e) { MessageBox.Show(e.Message); // 处理案例1的严重错误 } finally { // 清理上下文,避免影响后续模拟 WarningContext.Current = null; } } public bool ShowAlternativeInquiryMessage() => MessageBox.Show("D为0,若预期此情况请点击Yes,否则点击No尝试替代计算", "", MessageBoxButton.YesNo) == MessageBoxResult.No; } public class SimulationCore { public void RunSimulation() => PhysicsSimulationRunner.RunPhysics(); public static class PhysicsSimulationRunner { public static void RunPhysics() { int a = 0; int b = 1 / a; // 案例1:抛出异常,由UI捕获 int c = GetValueC(); if (c > 1000) { // 无侵入添加警告,无需依赖注入 WarningContext.AddWarning("C值超过1000"); } int d = GetValueD(); if (d == 0) { // 案例2的逻辑见下文 } } public static int GetValueC() => 1001; public static int GetValueD() => 0; public static int GetValueDAlt() => 5; } }
案例2:模拟暂停与用户交互的解耦方案
实现思路
采用回调委托+抽象交互契约实现解耦:
- 核心模拟代码接受一个
Func<SimulationRequest, object>类型的回调委托,该委托由UI层实现 - 当需要用户交互时,核心代码创建抽象的交互请求对象,调用回调委托获取用户输入
- 核心代码仅依赖抽象的交互请求模型,完全不耦合具体UI实现
修改后代码
// 抽象交互请求契约,核心代码仅依赖此类型 public abstract class SimulationRequest { // 定义交互逻辑的执行入口,由UI层实现具体行为 public abstract object Execute(Ui ui); } // 案例2的具体交互请求 public class AlternativeCalculationRequest : SimulationRequest { public override object Execute(Ui ui) => ui.ShowAlternativeInquiryMessage(); } public class Ui { public void RunSimulationCommand() { var sim = new SimulationCore(); var warningsHandler = new WarningsHandler(); WarningContext.Current = warningsHandler; try { // 传递UI实现的交互回调给核心模拟 sim.RunSimulation(request => request.Execute(this)); foreach (var warning in warningsHandler.Warnings) { MessageBox.Show(warning); } } catch (Exception e) { MessageBox.Show(e.Message); } finally { WarningContext.Current = null; } } public bool ShowAlternativeInquiryMessage() => MessageBox.Show("D为0,若预期此情况请点击Yes,否则点击No尝试替代计算", "", MessageBoxButton.YesNo) == MessageBoxResult.No; } public class SimulationCore { // 核心模拟方法接受交互回调参数 public void RunSimulation(Func<SimulationRequest, object> interactionCallback) => PhysicsSimulationRunner.RunPhysics(interactionCallback); public static class PhysicsSimulationRunner { public static void RunPhysics(Func<SimulationRequest, object> interactionCallback) { int a = 0; int b = 1 / a; int c = GetValueC(); if (c > 1000) { WarningContext.AddWarning("C值超过1000"); } int d = GetValueD(); if (d == 0) { // 创建交互请求,调用回调获取用户选择 bool tryAlternative = (bool)interactionCallback(new AlternativeCalculationRequest()); if (tryAlternative) { d = GetValueDAlt(); } } // 继续执行后续模拟逻辑 } public static int GetValueC() => 1001; public static int GetValueD() => 0; public static int GetValueDAlt() => 5; } }
内容的提问来源于stack exchange,提问作者aluc_2513
相关产品推荐
相关产品推荐

