如何将带Lambda表达式参数的泛型方法作为委托传递?
当然可以实现!这里有两种清晰的解决方案
你的核心需求是在传递泛型方法作为委托时,同时携带Lambda过滤器参数——其实只需要调整委托类型或者利用闭包捕获就能搞定,下面我会结合你的代码给出具体修改方案:
先明确基础修改:让加载方法支持过滤器
首先我们需要把LoadFromDBAsync和GetAllItemsFromTableAsync调整为支持接收过滤器参数,这是后续所有逻辑的基础:
/// <summary> /// 视图模型中的加载方法,现在支持接收过滤器 /// </summary> protected virtual async Task<TCollection> LoadFromDBAsync<TColItemType, TCollection>( Expression<Func<TColItemType, bool>> filter = null) where TCollection : List<TColItemType>, new() where TColItemType : new() { // 这里可以添加自定义预处理逻辑(比如权限检查、日志) return (TCollection)await GetAllItemsFromTableAsync<TColItemType>(filter); } /// <summary> /// 数据库查询方法,现在接收过滤器并传递给底层DB方法 /// </summary> protected async Task<List<TColItemType>> GetAllItemsFromTableAsync<TColItemType>( Expression<Func<TColItemType, bool>> filter = null) where TColItemType : new() { // 准备工作、空值检查等 return await database.GetAllWithChildrenAsync<TColItemType>(recursive: true, filter: filter); }
方案一:修改LoadPickerAsync,直接传递过滤器和带参数的委托
这个方案更直观,适合需要在LoadPickerAsync内部访问过滤器逻辑的场景:
调整LoadPickerAsync的签名
新增过滤器参数,并把委托类型改为接收过滤器、返回异步任务的类型:
protected virtual async Task<TCollection> LoadPickerAsync<TColItemType, TViewModel, TCollection>( PropertyInfo collectionProperty, PropertyInfo indexProperty, PropertyInfo objectProperty, Expression<Func<TColItemType, bool>> filter, // 新增过滤器参数 Func<Expression<Func<TColItemType, bool>>, Task<TCollection>> collectionLoaderAsync) where TCollection : List<TColItemType> { // 对属性执行特殊操作(比如校验、初始化) // 调用加载方法并传递过滤器 var loadedCollection = await collectionLoaderAsync(filter); if (loadedCollection != default(TCollection)) { // 执行后续操作(比如设置加载完成标志、更新UI) } return loadedCollection; }
在RefreshControls中调用
直接传递过滤器Lambda和LoadFromDBAsync方法作为委托:
protected async Task RefreshControls() { await LoadPickerAsync<Car, ViewModel<Car>, List<Car>>( this.GetPropertyInfo(x => x.AvailableColors), this.GetPropertyInfo(y => y.ColorIndex), this.GetPropertyInfo(z => z.Color), x => x.ID == 4, // 传递Car的过滤器 LoadFromDBAsync<Colors, List<Colors>>); await LoadPickerAsync<Truck, ViewModel<Truck>, List<Truck>>( this.GetPropertyInfo(x => x.AvailableColors), this.GetPropertyInfo(y => y.ColorIndex), this.GetPropertyInfo(z => z.Color), x => x.ID == 3, // 传递Truck的过滤器 LoadFromDBAsync<Colors, List<Colors>>); }
方案二:利用闭包捕获过滤器,保持原有LoadPickerAsync签名
如果不想修改LoadPickerAsync的原有结构,可以用闭包把过滤器绑定到委托中,传递一个无参数的委托给LoadPickerAsync:
保持LoadPickerAsync的原有签名
不需要做任何修改,还是原来的无参数委托类型:
protected virtual async Task<TCollection> LoadPickerAsync<TColItemType, TViewModel, TCollection>( PropertyInfo collectionProperty, PropertyInfo indexProperty, PropertyInfo objectProperty, Func<Task<TCollection>> collectionLoaderAsync) where TCollection : List<TColItemType> { // 原有逻辑不变 var loadedCollection = await collectionLoaderAsync(); if (loadedCollection != default(TCollection)) { // 执行后续操作 } return loadedCollection; }
在RefreshControls中用闭包绑定过滤器
用Lambda表达式包裹LoadFromDBAsync,把过滤器参数“打包”成无参数委托:
protected async Task RefreshControls() { await LoadPickerAsync<Car, ViewModel<Car>, List<Car>>( this.GetPropertyInfo(x => x.AvailableColors), this.GetPropertyInfo(y => y.ColorIndex), this.GetPropertyInfo(z => z.Color), () => LoadFromDBAsync<Colors, List<Colors>>(x => x.ID == 4)); // 闭包捕获过滤器 await LoadPickerAsync<Truck, ViewModel<Truck>, List<Truck>>( this.GetPropertyInfo(x => x.AvailableColors), this.GetPropertyInfo(y => y.ColorIndex), this.GetPropertyInfo(z => z.Color), () => LoadFromDBAsync<Colors, List<Colors>>(x => x.ID == 3)); }
关键知识点解释
- 闭包:方案二中的
() => LoadFromDBAsync(...)就是闭包,它会捕获x => x.ID ==4这个Lambda表达式,把带参数的方法转换成LoadPickerAsync需要的无参数委托。 - 委托类型匹配:方案一中的
Func<Expression<Func<TColItemType, bool>>, Task<TCollection>>表示“一个接收过滤器表达式、返回异步任务的方法”,正好匹配修改后的LoadFromDBAsync签名,所以可以直接传递方法名作为委托。
两种方案都能满足你的需求,选择哪一种取决于你是否需要在LoadPickerAsync内部直接访问过滤器逻辑~
内容的提问来源于stack exchange,提问作者MREme
相关产品推荐
相关产品推荐

