代码之家  ›  专栏  ›  技术社区  ›  Martin Hansen Lennox

如何创建和调用缓存GetOrSet方法的异步版本?

  •  3
  • Martin Hansen Lennox  · 技术社区  · 8 年前

    我正在尝试创建一个 async 低级别缓存服务的版本。

    标准非异步版本如下所示:

    public class ApplicationCachingService : IApplicationCacheService
    {
        public T GetOrSet<T>(string cacheKey, Func<T> getDataCallback) 
            where T : class
        {
            T data = HttpContext.Current.Application[cacheKey] as T;
            if (data == null)
            {
                data = getDataCallback();
                HttpContext.Current.Application[cacheKey] = data;
            }
            return data;
        }
    
    
        public void ClearCache(string cacheKey)
        {
            HttpContext.Current.Application[cacheKey] = null;
        }
    }
    

    我添加了以下方法。

        public async Task<T> GetOrSetAsync<T>(string cacheKey, Task<Func<T>> getDataCallback) 
            where T : class
        {
            T data = HttpContext.Current.Application[cacheKey] as T;
            if (data == null)
            {
                Func<Task<Func<T>>> myFunc = async () => await getDataCallback;
                var funcResult = await myFunc();
                data = funcResult();
                HttpContext.Current.Application[cacheKey] = data;
            }
            return data;
        }
    

    问题1-这是正确的方法吗?

    我不确定是否需要创建 funcResult 变量,或者是否有更简洁的方法。例如,这条线看起来可能不必要地复杂 Func<Task<Func<T>>> myFunc = async () => await getDataCallback;

    以上是基于纯粹的代码伪造,就代理而言,我是个十足的傻瓜。

    问题2-我该如何称呼它?

    我将此代码用于标准非异步版本:

    var items = cachingService.GetOrSet<IList<BlogPostDataModel>>(
        "BlogPostsIndex",
        () => repository.GetAll<BlogPostDataModel>()
        );
    

    我将此代码用于异步版本:

    var items = await cachingService.GetOrSetAsync<IList<BlogPostDataModel>>(
        "BlogPostsIndex",
        () => await repository.GetAllAsync<BlogPostDataModel>()
    );
    

    但是异步版本给了我 cannot convert lambda expression to type Task<Func<IList<BlogPostDataModel>>>' because it is not a delegate type


    最终工作示例

    CodeFuller的回答很有帮助,读完后我马上就找到了答案。以下是完整的工作代码:

    public interface IApplicationCacheService
    {
        T GetOrSet<T>(string cacheKey, Func<T> getDataCallback) where T : class;
        Task<T> GetOrSetAsync<T>(string cacheKey, Func<Task<T>> getDataCallback) where T : class;
    }
    
    
    public class ApplicationCachingService : IApplicationCacheService
    {
        public T GetOrSet<T>(string cacheKey, Func<T> getDataCallback) 
            where T : class
        {
            T data = HttpContext.Current.Application[cacheKey] as T;
            if (data == null)
            {
                data = getDataCallback();
                HttpContext.Current.Application[cacheKey] = data;
            }
            return data;
        }
    
    
        public async Task<T> GetOrSetAsync<T>(string cacheKey, Func<Task<T>> getDataCallback) 
            where T : class
        {
            T data = HttpContext.Current.Application[cacheKey] as T;
            if (data == null)
            {
                data = await getDataCallback();
                HttpContext.Current.Application[cacheKey] = data;
            }
            return data;
        }
    
    
        public void ClearCache(string cacheKey)
        {
            HttpContext.Current.Application[cacheKey] = null;
        }
    }
    

    这样称呼:

    var items = await cachingService.GetOrSetAsync(
        cacheKey,
        () => repository.GetAllAsync<BlogPostDataModel>()
    );
    
    1 回复  |  直到 8 年前
        1
  •  2
  •   CodeFuller    8 年前

    getDataCallback 具有类型 Task<Func<T>> . 我相信(根据 GetOrSetAsync 方法)您的意图是 Task 那会回来的 Func<T> 但要通过一个异步值工厂,即。 Func<Task<T>> .

    所以第一步是更改 GetOrSetAsync<T> :

    在里面 IApplicationCacheService 接口:

    Task<T> GetOrSetAsync<T>(string cacheKey, Func<Task<T>> getDataCallback) where T : class;
    

    并且在 ApplicationCachingService 类别:

    public async Task<T> GetOrSetAsync<T>(string cacheKey, Func<Task<T>> getDataCallback) where T : class
    

    现在你可以打电话了 await getDataCallback() 要从回调中获取值,请执行以下操作:

    public async Task<T> GetOrSetAsync<T>(string cacheKey, Func<Task<T>> getDataCallback) where T : class
    {
        T data = HttpContext.Current.Application[cacheKey] as T;
        if (data == null)
        {
            data = await getDataCallback();
            HttpContext.Current.Application[cacheKey] = data;
        }
        return data;
    }
    

    现在,让我们修复呼叫 GetOrSetAsync . If存储库方法 GetAllAsync 声明为:

    Task<IList<T>> GetAllAsync<T>() where T : class;
    

    那么这是一个lambda,你应该传给 IApplicationCacheService.GetOrSetAsync :

    () => repository.GetAllAsync<BlogPostDataModel>()
    

    因为 GetAllAsync<BlogPostDataModel>() 退货 Task<IList<BlogPostDataModel>> 和lambda () => repository.GetAllAsync<BlogPostDataModel>() 类型为 Func<Task<IList<BlogPostDataModel>>> 这正是预期的类型 IApplicationCacheService.GetOrSetAsync<IList<BlogPostDataModel>>() .

    你不应该打电话 await 在…上 GetAllAsync() 在lambda。 等候 将在内部调用 ApplicationCachingService.GetAllAsync() 在返回的任务上 getDataCallback .

    下面是正确的电话 cachingService.GetOrSetAsync :

    var items = await cachingService.GetOrSetAsync<IList<BlogPostDataModel>>(
        "BlogPostsIndex",
        () => repository.GetAllAsync<BlogPostDataModel>()
    );