You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于传入对象类型实现OData响应结果的泛型JSON反序列化

这个需求完全可以实现,两种常见实现方案如下:

方案1:泛型重构(推荐,类型安全性能高)

第一步:改造响应类为泛型

// 把原来的非泛型EntityListResponse改成泛型类,直接指定Records的元素类型
public class EntityListResponse<T>
{
    [System.Text.Json.Serialization.JsonPropertyName("value")]
    public List<T> Records { get; set; }
    
    [System.Text.Json.Serialization.JsonPropertyName("@odata.count")]
    public int Total { get; set; }
}

第二步:改造通用服务的GetAll方法为泛型

// 方法添加泛型参数,不需要再传object类型的entity
public async Task<EntityListResponse<T>> GetAll<T>(DataSourceRequest request)
{
    // 直接通过泛型参数拿类型名构造请求路径,避免实体ToString重写导致路径错误
    var baseUrl = $"{typeof(T).Name}s?";
    var requestUrl = $"{baseUrl}{request.ToODataString()}";

    var requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUrl);
    requestMessage.Headers.Add("Accept", "application/json");
    var client = HttpClient.CreateClient("IndiciaStageApi");
    var response = await client.SendAsync(requestMessage);

    if (response.IsSuccessStatusCode)
    {
        var body = await response.Content.ReadAsStringAsync();
        var options = new JsonSerializerOptions();
        options.Converters.Add(new JsonStringEnumConverter());
        // 直接反序列化为对应泛型类型的响应,Records自动就是List<T>类型
        var oDataResponse = JsonSerializer.Deserialize<EntityListResponse<T>>(body, options);
        return oDataResponse;
    }
    else
    {
        throw new HttpRequestException("Request failed. I need better error handling, e.g. returning empty data.");
    }
}

第三步:Blazor组件侧调用

因为你的组件已经定义了TItem泛型参数,直接传入即可:

private async Task ReadEntity(GridReadEventArgs args)
{
    var data = await _entityService.GetAll<TItem>(args.Request);
    // 此处data.Records自动就是List<TItem>类型,无需额外类型转换
}

方案2:反射动态构造类型(兼容原有非泛型方法签名)

如果你不想改动现有方法的入参定义,也可以通过反射动态生成反序列化目标类型实现需求:

public async Task<EntityListResponse> GetAll(DataSourceRequest request, object entity)
{
    Type entityType = entity.GetType();
    var baseUrl = $"{entityType.Name}s?";
    var requestUrl = $"{baseUrl}{request.ToODataString()}";

    var requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUrl);
    requestMessage.Headers.Add("Accept", "application/json");
    var client = HttpClient.CreateClient("IndiciaStageApi");
    var response = await client.SendAsync(requestMessage);

    if (response.IsSuccessStatusCode)
    {
        var body = await response.Content.ReadAsStringAsync();
        var options = new JsonSerializerOptions();
        options.Converters.Add(new JsonStringEnumConverter());
        
        // 动态构造对应实体类型的泛型响应类
        Type genericResponseType = typeof(EntityListResponse<>).MakeGenericType(entityType);
        dynamic oDataResponse = JsonSerializer.Deserialize(body, genericResponseType, options);
        
        // 转换为原有非泛型响应类返回
        return new EntityListResponse
        {
            Total = oDataResponse.Total,
            Records = oDataResponse.Records
        };
    }
    else
    {
        throw new HttpRequestException("Request failed. I need better error handling, e.g. returning empty data.");
    }
}

该方案返回的Records列表内部元素已经是对应实体类型,使用时通过Records.Cast<目标类型>()转换即可。

注意事项

  • 原有代码中使用$"{entity}s?"拼接请求路径存在风险,如果实体类重写了ToString方法会导致路径错误,统一使用typeof(T).Name或者entity.GetType().Name获取类型名更稳妥。
  • 优先选择泛型方案,无需反射开销,类型安全,编译阶段就能排查类型不匹配问题。

内容的提问来源于stack exchange,提问作者Stefan Jaspers

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 16:27:03