对象缓存实现

有这么一种场景,对于某个指定的接口,你需要得到它的一个实例,首先你从一个缓存中取,如果有就返回,否则调用一个指定的 delegate 来得到这个实例。假设有接口和实现:

    public interface IBar { }

    public class Bar : IBar {
        public string Name { get; private set; }
        public Bar(string name) {
            this.Name = name;
        }
    }

    public class TestBar : IBar { 

    }

 

我希望通过某种方式来获取对象, 如果有缓存(假设一个TestBar的对象)就取它,否则 new Bar(“Hello”):

    Cache.Get<IBar>("Hello");

 

我的第一个实现采用了一个Dictionary, 缓存了Type –> Object + Delegate 对:

    public static class DictCache
    {
        private class CachedObj
        {
            public object Instance { get; set; }
            public Delegate Callback { get; set; }
        }

        private static IDictionary<Type, CachedObj> cache = new Dictionary<Type, CachedObj>();

        public static T Get<T>(params object[] arguments)
        {
            CachedObj pair;
            if (!cache.TryGetValue(typeof(T), out pair))
            {
                throw new InvalidOperationException();
            }

            return (T)(pair.Instance ?? pair.Callback.DynamicInvoke(arguments));
        }

        public static void Set<T>(object instance, Expression<Func<T>> exp)
        {
            SetMapping<T>(instance, exp);
        }

        public static void Set<P, T>(object instance, Expression<Func<P, T>> exp)
        {
            SetMapping<T>(instance, exp);
        }

        public static void Set<T>(object instance, LambdaExpression exp)
        {
            SetMapping<T>(instance, exp);
        }

        private static void SetMapping<T>(object instance, LambdaExpression exp)
        {
            cache[typeof(T)] = new CachedObj { Instance = instance, Callback = exp.Compile() };
        }
    }

 

在这个实现里,主要利用了Delegate来延迟创建对象,重载Set 方法是为了方便。

 

首先我们可以缓存这个对象:

            DictCache.Set<string, IBar>(new TestBar(), name => new Bar(name));

 

然后取用:

            IBar bar = DictCache.Get<IBar>("Hello");

 

考虑到在这个实现中使用 Delegate 的 DynamicInvoke 方法,可能会有一些Performance 问题,我的第二个方法使用静态类,并且把Delegate作为类型参数:

    public static class StaticCache
    {
        private static class Cached<T, TDelegate>
        {
            public static T Instance { get; set; }
            public static TDelegate Callback { get; set; }
        }

        public static T Get<T>() where T : class
        {
            return (T) (Cached<T, Func<T>>.Instance ?? Cached<T, Func<T>>.Callback());
        }

        public static T Get<P, T>(P p) where T : class
        {
            return (T)(Cached<T, Func<P, T>>.Instance ?? Cached<T, Func<P, T>>.Callback(p));
        }

        public static void Set<T>(T instance, Expression<Func<T>> exp)
        {
            SetMapping<T, Func<T>>(instance, exp);
        }

        public static void Set<P, T>(T instance, Expression<Func<P, T>> exp)
        {
            SetMapping<T, Func<P, T>>(instance, exp);
        }

        public static void SetMapping<T, TDelegate>(T instance, Expression<TDelegate> exp)
        {
            Cached<T, TDelegate>.Instance = instance;
            Cached<T, TDelegate>.Callback = exp.Compile();
        }
    }

 

这个方案,效率上会有提高,但是需要更多的Get 和 Set 的重载,以针对不同的参数类型和个数, 用法如下:

            StaticCache.Set<string, IBar>(null, name => new Bar(name));

 

获取:

            IBar bar = StaticCache.Get<string, IBar>("name");

 

是否还有其他的更简单的方法呢?发挥我们的创造力!

转载于:https://www.cnblogs.com/oujinliang/archive/2009/12/03/1616261.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值