通过委托访问值类型:Blazor组件数据更新失效问题
问题分析与解决方案
核心问题
你当前代码无法修改底层数据的原因是:itemEdited委托返回的是值类型(decimal)的副本。值类型在传递时按值复制,你对itemEd的赋值操作只会修改这个副本,完全不会影响原AtomicMetric对象的JobValue属性。
解决方案
把负责属性选择的Func<TEdit, Object>委托,替换成能直接修改属性的Action<TEdit, object>委托(或更类型安全的泛型版本),让委托内部直接完成属性赋值操作,而非返回值类型副本。
步骤1:修改事件处理方法
将HandleEvent的第三个参数从Func<TEdit, Object>改为Action<TEdit, object>,直接调用委托完成赋值:
private void HandleEvent(List<TEdit> editItems, Func<List<TEdit>, TEdit> itemEditedFilter, Action<TEdit, object> itemSetter) { var itemToChange = itemEditedFilter(editItems); if (itemToChange == null) return; // 增加空值判断,避免空引用异常 // 直接调用委托修改原对象的属性 itemSetter(itemToChange, editedValue); }
步骤2:更新委托定义
在Blazor组件中,把ItemEdited的委托改成直接赋值的逻辑,而非返回属性值:
ItemEdited="@((PeriodicMetricDTO x, object newValue) => x.cf.JobValue = Convert.ToDecimal(newValue))"
(可选)类型安全优化版本
如果想避免装箱拆箱和类型转换的潜在问题,可以使用带泛型参数的版本:
private void HandleEvent<TProperty>(List<TEdit> editItems, Func<List<TEdit>, TEdit> itemEditedFilter, Action<TEdit, TProperty> itemSetter) { var itemToChange = itemEditedFilter(editItems); if (itemToChange == null) return; // 类型检查确保转换安全 if (editedValue is TProperty newValue) { itemSetter(itemToChange, newValue); } }
对应的委托定义更简洁:
ItemEdited="@((PeriodicMetricDTO x, decimal newValue) => x.cf.JobValue = newValue)"
原理说明
AtomicMetric是引用类型,x.cf指向堆上的实际对象。通过Action委托直接访问x.cf.JobValue并赋值,本质是对堆上对象的属性进行修改,因此会直接同步到底层数据集。而原来的Func返回值类型时,只是把值复制出来,修改副本不会影响原对象。
内容的提问来源于stack exchange,提问作者Rich Freeman
相关产品推荐
相关产品推荐

