在异步上下文中使用Language-ext的Bind操作
使用language-ext处理异步Option链式调用的优化方案
问题背景
在C#中使用language-ext包提升代码健壮性时,链式调用异步操作遇到了困难,以下是具体场景和代码:
基础代码定义
车辆抽象类
public class MyVehicle { public MyVehicle(string name) { Name = name; } public string Name { get; } public MyVehicle DeepCopy() { return new MyVehicle(Name); } }
车辆状态类
public class MyVehicleState { public MyVehicle CopiedVehicle { get; private set; } public Option<int> EditingId { get; set; } public void SetCopiedVehicle(MyVehicle vehicle) { CopiedVehicle = vehicle; } }
同步仓储实现
public class MyVehicleRepository { public Option<MyVehicle> GetVehicle(int id) { return id == 2 ? Some(new MyVehicle("Delorian")) : Option<MyVehicle>.None; } }
同步场景实现
将MyVehicleState的CopiedVehicle设置为EditingId对应车辆的深拷贝,同步场景的实现如下:
var state = new MyVehicleState { EditingId = Some(2) }; var repo = new MyVehicleRepository(); state.EditingId .Bind(vehicleId => repo.GetVehicle(vehicleId)) .Map(vehicle => vehicle.DeepCopy()) .IfSome(copiedVehicle => state.SetCopiedVehicle(copiedVehicle));
异步场景的问题
当仓储改为异步实现后:
public class MyVehicleRepository { public async Task<Option<MyVehicle>> GetVehicle(int id) { await Task.Delay(TimeSpan.FromSeconds(2)); return id == 2 ? Some(new MyVehicle("Delorian")) : Option<MyVehicle>.None; } }
尝试使用BindAsync和MapAsync时出现需两次解包的问题,自行实现的可行写法如下,但不确定是否为最优解:
await state.EditingId .MapAsync(async vehicleId => await repo.GetVehicle(vehicleId)) .IfSome(x => x .Map(y => y.DeepCopy()) .IfSome(z => state.SetCopiedVehicle(z)));
优化后的异步实现
你给出的写法是可行的,但可以利用language-ext的原生方法进一步简化,避免嵌套的IfSome处理:
var state = new MyVehicleState { EditingId = Some(2) }; var repo = new MyVehicleRepository(); await state.EditingId .BindAsync(repo.GetVehicle) // 直接绑定异步仓储方法,自动处理Task<Option<T>>的解包 .Map(vehicle => vehicle.DeepCopy()) // 同步映射深拷贝操作 .IfSomeAsync(copiedVehicle => state.SetCopiedVehicle(copiedVehicle)); // 异步回调处理结果
关键说明
BindAsync:专门适配Option<A>绑定返回Task<Option<B>>的函数,自动完成异步操作和Option的解包,无需手动嵌套处理Task和Option。Map:由于DeepCopy是同步方法,直接使用Map对Option<MyVehicle>内的值执行映射即可,无需异步版本。IfSomeAsync:当Option存在有效值时执行回调,即使回调是同步方法也能兼容,保持链式异步风格的一致性。
如果后续DeepCopy改为异步方法,只需替换为MapAsync即可:
await state.EditingId .BindAsync(repo.GetVehicle) .MapAsync(async vehicle => await vehicle.DeepCopyAsync()) .IfSomeAsync(copiedVehicle => state.SetCopiedVehicle(copiedVehicle));
内容的提问来源于stack exchange,提问作者James B
相关产品推荐
相关产品推荐

