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

Castle动态代理缓存切面:运行时类型转换异常求助

解决方案

1. 核心问题分析

你遇到的两个类型不匹配问题本质是:

  • 直接调用Task.FromResult(cachedValue)会生成Task<object>,但被拦截方法返回的是Task<T>(T为运行时确定的具体类型),导致类型转换失败。
  • 缓存反序列化返回的是具体实现类(如List<MovieResponse>),但方法声明返回接口/父类型(如IEnumerable<MovieResponse>),直接赋值会引发类型转换异常。

2. 修复后的代码实现

public class CacheAspect : MethodInterception
{
    private readonly int _duration;
    private readonly string _key;
    private readonly ICacheService _cacheService;

    public CacheAspect(string key, int duration)
    {
        _key = key;
        _duration = duration;
        _cacheService = ServiceTool.ServiceProvider.GetService<ICacheService>();
    }

    public override async void Intercept(IInvocation invocation)
    {
        // 获取被拦截方法返回的Task<T>中的泛型参数T
        var resultType = invocation.Method.ReturnType.GetGenericArguments()[0];
        var cachedValue = _cacheService.Get(_key, resultType);

        if (cachedValue is not null)
        {
            // 处理具体类型到接口/父类型的转换(如List转IEnumerable)
            object convertedValue;
            try
            {
                convertedValue = Convert.ChangeType(cachedValue, resultType);
            }
            catch (InvalidCastException)
            {
                // 转换失败时 fallback 到原方法执行
                invocation.Proceed();
                var returnValue = await (dynamic)invocation.ReturnValue;
                _cacheService.Add(_key, returnValue, TimeSpan.FromHours(_duration));
                return;
            }

            // 通过反射创建正确泛型类型的Task<T>,避免Task<object>类型不匹配
            var fromResultMethod = typeof(Task).GetMethod(nameof(Task.FromResult))
                .MakeGenericMethod(resultType);
            invocation.ReturnValue = fromResultMethod.Invoke(null, new[] { convertedValue });
            return;
        }

        // 缓存未命中时执行原方法并缓存结果
        invocation.Proceed();
        var returnValue = await (dynamic)invocation.ReturnValue;
        _cacheService.Add(_key, returnValue, TimeSpan.FromHours(_duration));
    }
}

3. 关键逻辑说明

  • 动态创建泛型Task:通过反射获取Task.FromResult<T>的泛型版本,传入转换后的缓存值,生成与被拦截方法返回类型完全一致的Task<T>,解决Task<object>转Task<IEnumerable<T>>的异常。
  • 类型转换处理:Convert.ChangeType支持引用类型的向上转换(如实现类转接口),确保缓存值类型与方法声明的返回类型匹配,解决List<T>转IEnumerable<T>的异常。

4. 可选优化建议

  • 替换async void:async void是异步编程的不良实践,容易导致未捕获异常。如果你的Castle版本支持,建议改用IAsyncInterceptor实现异步拦截,更符合异步编程规范。
  • 缓存序列化优化:在反序列化时,可以尝试直接将JSON序列化为接口对应的代理类型,但需要自定义JsonConverter,不过上述代码的转换逻辑已能覆盖大部分场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 17:02:53