如何移除泛型方法GetAllPagesAsync中的V类型参数以避免重复定义?
如何移除泛型方法GetAllPagesAsync中的V类型参数以避免重复定义?
我完全懂这种重复指定泛型参数的烦躁感——明明FabricContactsResponse已经明确了它的泛型类型是FabricContactDTO,还要在调用GetAllPagesAsync时再写一遍,确实多余。咱们可以通过给泛型基类加一个非泛型接口的方式,把V参数彻底去掉,同时保持类型安全,下面是具体的实现步骤:
1. 定义非泛型接口,统一分页响应的公共属性
首先我们需要一个非泛型的接口,把GetAllPagesAsync里要用到的分页和数据属性暴露出来,这样就不需要依赖具体的V类型了:
public interface IFabricListResponse { // 用IEnumerable而非强类型List,因为我们只需要遍历数据,不需要知道具体元素类型 IEnumerable Data { get; } int TotalPages { get; } int CurrentPage { get; } }
2. 让泛型基类实现这个接口
修改你的FabricListResponse<V>基类,让它实现上面的接口,同时保留原来的强类型Data属性,不影响其他地方的使用:
public class FabricListResponse<V> : IFabricListResponse { // 原来的强类型数据属性,正常使用不受影响 public List<V> Data { get; set; } // 显式实现接口,避免非泛型的Data属性干扰强类型场景 IEnumerable IFabricListResponse.Data => Data; // 保留你原来的分页属性 public int TotalPages { get; set; } public int CurrentPage { get; set; } }
3. 重构GetAllPagesAsync,移除冗余的V参数
现在可以把GetAllPagesAsync的V泛型参数删掉,同时把泛型约束改成U : IFabricListResponse,确保我们能访问到需要的属性:
private async Task<List<T>> GetAllPagesAsync<T, U>(string endpoint, ILogger log) where T : class where U : IFabricListResponse, class { var contacts = new List<T>(); U fabricApiResponse; var page = 1; do { fabricApiResponse = await apiService.GetAPIResponseAsync<U>(endpoint, page, log); // 接口的Data是IEnumerable,映射器(比如AutoMapper)可以自动处理成List<T> contacts.AddRange(mapper.Map<List<T>>(fabricApiResponse.Data)); page++; } while (fabricApiResponse.TotalPages > fabricApiResponse.CurrentPage); return contacts; }
4. 简化调用代码,去掉重复的V参数
现在调用GetAllPagesAsync时,只需要传T和U两个泛型参数就够了,再也不用重复指定V:
public async Task<ContactsResponse> GetAccountContactsAsync(string accountId, ILogger log) { // 现在只需要两个泛型参数:目标DTO类型和API响应类型 var contacts = await GetAllPagesAsync<ContactDTO, FabricContactsResponse>($"/v1/account/{accountId}/contacts", log); var response = new ContactsResponse { Contacts = mapper.Map<List<ContactDTO>>(contacts) }; return response; }
额外小提示
如果你的映射器对IEnumerable的支持不够友好,也可以把接口里的Data改成IEnumerable<object>,然后在FabricListResponse<V>里实现为:
IEnumerable<object> IFabricListResponse.Data => Data.Cast<object>();
这样映射器依然能正确识别元素类型,完成映射工作。
备注:内容来源于stack exchange,提问作者Ben Kleywegt
相关产品推荐
相关产品推荐

