实现 对象在内存中的引用一致性 之第一步

  • 原委

    废话不要,他们都该删。

    虽然写了个 基于数据库的代码生成器 与大家分享,但并不擅长数据库开发;相反,面向对象才是我的爱。
    多年的酝酿让我收获良多,直觉这是个令人激动的开发模式。

    或许是因为高中学历吧,我的思想还是朴素的:在实施软件开发时,第一反应是对象而不是数据库。

  • 实施

    朴素的思想让人选择朴素的视角,一种朴素的视角看到的是:

    Assert.AreSame(employee1.Department, employee2.Department);

    或许更适用些的断言是:

    if (model1.Id == model2.Id)
        Assert.AreSame(model1, model2);

    实现此断言即是实现 对象在内存中的唯一性,不过我还是觉得叫 对象在内存中的引用一致性 贴切点;
    开始实现吧。

     

    假设我们已经分析过业务了,那接下来的第一步当然是业务模型的建立了,这一步很是顺其自然且乏味地就能 下载到结果
    Northwind1

    紧接上一步,我们发现了一个显眼的问题:大值属性。
    这真是个好问题,让人莫名地开心起来。

    这个问题的解决就是我们第二步需要做的了,不过还是妙手偶得之地就能 下载到结果
    CachedProperties

    实现的要点在这里:

    using System;
    using System.Runtime.Caching;
    
    namespace Codesir.Net.Identical
    {
        /// <summary>
        /// 实现软引用,同时具备 缓存的长时效 和 弱引用的一致性 优点。
        /// </summary>
        public class CachedWeakReference<T>
            where T : class
        {
            static MemoryCache DefaultMemoryCache = MemoryCache.Default;
            static CacheItemPolicy DefaultCacheItemPolicy = new CacheItemPolicy { SlidingExpiration = TimeSpan.FromMinutes(20) };
    
            WeakReference weakReference;
            MemoryCache memoryCache;
            CacheItemPolicy cacheItemPolicy;
            string cacheKey;
    
            /// <summary>
            /// 使用指定的对象初始化一个软引用实例。
            /// </summary>
            /// <param name="target">要缓存并跟踪的对象。</param>
            public CachedWeakReference(T target)
                : this(target, CachedWeakReference<T>.DefaultMemoryCache, CachedWeakReference<T>.DefaultCacheItemPolicy)
            { }
            /// <summary>
            /// 使用指定的对象和缓存选项初始化一个软引用实例。
            /// </summary>
            /// <param name="target">要缓存并跟踪的对象。</param>
            /// <param name="memoryCache">要跟踪的对象加入到的内存缓存。</param>
            /// <param name="cacheItemPolicy">要跟踪的对象的缓存过期策略。</param>
            public CachedWeakReference(T target, MemoryCache memoryCache, CacheItemPolicy cacheItemPolicy)
            {
                if (target == null) throw new ArgumentNullException("target");
                if (memoryCache == null) throw new ArgumentNullException("memoryCache");
                if (cacheItemPolicy == null) throw new ArgumentNullException("cacheItemPolicy");
    
                this.weakReference = new WeakReference(target);
                this.memoryCache = memoryCache;
                this.cacheItemPolicy = cacheItemPolicy;
                this.cacheKey = Guid.NewGuid().ToString();
    
                this.memoryCache.Set(this.cacheKey, target, this.cacheItemPolicy);
            }
    
            /// <summary>
            /// 获取或设置当前软引用实例所引用的对象。
            /// </summary>
            public T Target
            {
                get
                {
                    T target = null;
    
                    T targetFromCache = this.memoryCache.Get(this.cacheKey) as T;
                    if (targetFromCache == null) //如果已从内存缓存移出
                    {
                        T targetByReference = this.weakReference.Target as T;
                        if (targetByReference != null) //但引用依然有效
                        {
                            this.memoryCache.Set(this.cacheKey, targetByReference, this.cacheItemPolicy); //则继续受内存缓存管理
                            target = targetByReference;
                        }
                    }
                    else
                    {
                        target = targetFromCache;
                    }
    
                    return target;
                }
                set
                {
                    if (value == null) throw new ArgumentNullException("value");
    
                    this.weakReference.Target = value;
                    this.memoryCache.Set(this.cacheKey, value, this.cacheItemPolicy);
                }
            }
        }
    }

     

    上段代码看上去还行,不过接下来的这个就狗便了,不知有没好心人优化下,在 CachedWeakReferenceProperty 里:

    /// <summary>
    /// 获取或设置属性值,值的重建已线程安全。
    /// </summary>
    public TProperty Value
    {
        get
        {
            TProperty value = null;
    
            if (this.isNull.HasValue && !this.isNull.Value && this.weakReference != null)
                value = this.weakReference.Target;
    
            if (this.owner.HasPersisted //只有已持久化才可能被重建
                && (this.isNull == null || (this.isNull.HasValue && this.isNull.Value && value == null))) //从未重建 或 已被回收 则需重建
            {
                lock (this)
                {
                    if (this.isNull == null || (this.isNull.HasValue && this.isNull.Value && this.weakReference.Target == null))
                    {
                        value = this.reconstructFunc();
    
                        this.isNull = value == null;
                        this.weakReference = value == null ? null : new CachedWeakReference<TProperty>(value);
                    }
                    else //双检失败是因为锁前线程已重建
                    {
                        if (this.weakReference != null)
                            value = this.weakReference.Target;
                    }
                }
            }
    
            return value;
        }
        set
        {
            this.isNull = value == null;
            this.weakReference = value == null ? null : new CachedWeakReference<TProperty>(value);
        }
    }

    今天就分享到这吧,还有更多更让人开心的问题等着我们呢。

posted @ 2013-07-02 11:01  JimHappy#真嗨皮#郑海滨  阅读(1315)  评论(3编辑  收藏  举报