• 对不能用using的成对操作,快速扩展IDisposable的方法


    日常操作中有很多需要打开/关闭   加锁/解锁的成对操作

    有时候一些操作原生支持  IDisposable
    Monitor 可以用Lock(){}   但是ReadWriteLock 就难了。 还有WCF Channel等)。
    这种情况就要用  try/catch/finally,很是丑

    封装成IDisposable可能很烦,因为多一个对象要多好多文档。

    虽然AOP可能解决一些问题, 但是又没办法精确定位  scrope. 
    还是 IDisposable +using最爽

    所以写了一个缺省实现。

        /// <summary>  
    
        /// 销毁帮手,生成可以支持using的自定义IDisposable实例
        /// <remarks>感谢网友@doggo对于 +=OnDispose功能的測試,由於不完善這裡決定取消該功能</remarks>
    
        /// </summary>  
    
        public struct Disposable : IDisposable
        {
    
    
       
            /// <summary>  
    
            /// 创建销毁帮手实例  
    
            /// </summary>  
    
            /// <param name="onCreate">创建时要做的操作</param>  
    
            /// <param name="onDispose">销毁是要做的操作</param>  
    
            public Disposable(Action onCreate, Action onDispose)
            {
                OnDispose = onDispose;
    
    
                onCreate();
    
            }
    
    
    
            /// <summary>  
    
            /// 销毁时要做的操作          
           /// </summary>  
    
            private Action OnDispose
            {
    
                    get ;set;
    
                 }  
    
            ////// <summary>  
    
            ////// 销毁时要做的操作  支持+=/Addhandler附加操作 (撤銷)  
    
            ////// </summary>  
    
            //////public event Action OnDispose ;
    
    
            #region IDisposable 成员
    
    
    
            void IDisposable.Dispose()
            {
    
            
                OnDispose();
    
                OnDispose = null;
    
            }
    
    
    
            #endregion
    
    
    
        } 
    
    

    思路是用一个扩展方法,给一个无dispose 能力的对象 建立一个IDisposable的引用。

    由于onCreate onDispose是闭包 额外的参数也是非必要的。

    这里提供一个简易读写锁的实现。  大家可以参考

        public static class ReaderWriteerLockSlimHelper 
        {
            /// <summary>
            /// 为读写锁创建支持using的IDisposable帮手
            /// </summary>
            /// <param name="instance">读写锁实例</param>
            /// <param name="lockType">加锁类型 读/写</param>
            /// <returns>帮手实例</returns>
            public static IDisposable CreateDisposable(this ReaderWriterLockSlim instance, LockType lockType)
            {
                var kvp = LockDisposeDic[lockType];
                return new Disposable(() => kvp.Key(instance), () => kvp.Value(instance));
            }
    
            /// <summary>
            /// 读写的不同操作字典
            /// </summary>
            static Dictionary<LockType, KeyValuePair<Action<ReaderWriterLockSlim>, Action<ReaderWriterLockSlim>>> LockDisposeDic = new Dictionary<LockType, KeyValuePair<Action<ReaderWriterLockSlim>, Action<ReaderWriterLockSlim>>>()
            {
                {
                    LockType.Read, 
                    new KeyValuePair<Action<ReaderWriterLockSlim>,Action<ReaderWriterLockSlim>> 
                        (
                            ins=>ins.EnterReadLock(),
                            ins=>ins.ExitReadLock()
                        ) 
                   
                },
                {
                    LockType.Write, 
                    new KeyValuePair<Action<ReaderWriterLockSlim>,Action<ReaderWriterLockSlim>> 
                        (
                            ins=>ins.EnterWriteLock(),
                            ins=>ins.ExitWriteLock()
                        ) 
                   
                }
            };
                
        }
    
        public enum LockType
        {
            Read,
            Write
        }
    

    实际使用起来就是爽。 这是一个在需要并发访问的队列中 加入对象的方法。

    /// <summary>
            /// 加入有序队列。
            /// </summary>
            /// <param name="item">加入的项目</param>
            public void Enqueue(TValue item)
            {
                using (_lock.CreateDisposable(LockType.Write))
                {
                    Queue<TValue> enqueueTarget;
                    var key=_keySelector(item);
                    if (!_items.ContainsKey(key))
                    {
                        var sortValue = _sortValueSelector(item);
                        if (!_index.TryGetValue( _sortValueSelector(item) ,out enqueueTarget ))
                        {
                            enqueueTarget = new Queue<TValue>();
                            _index.Add(sortValue, enqueueTarget);
                        }
    
                        enqueueTarget.Enqueue(item);
                        _items.Add(key, item);
                    }
                    else
                    {
                        throw new InvalidOperationException("this Item already in queue");
                    }
                }
    
            }
    

    个人工作分享。希望能够帮助大家提高工作效率

    附: 容易漏调结束行为的实现  和try catch finally 实现  大家比较下

      

       出异常会死锁的错误成对掉用 

            /// <summary>
            /// 加入有序队列。
            /// </summary>
            /// <param name="item">加入的项目</param>
            public void Enqueue1(TValue item)
            {
                _lock.EnterWriteLock();
    
        
                    Queue<TValue> enqueueTarget;
                    var key = _keySelector(item);
                    if (!_items.ContainsKey(key))
                    {
                        var sortValue = _sortValueSelector(item);
                        if (!_index.TryGetValue(_sortValueSelector(item), out enqueueTarget))
                        {
                            enqueueTarget = new Queue<TValue>();
                            _index.Add(sortValue, enqueueTarget);
                        }
    
                        enqueueTarget.Enqueue(item);
                        _items.Add(key, item);
                    }
                    else
                    {
                        throw new InvalidOperationException("this Item already in queue");
                    }
                    _lock.ExitReadLock(); //不但可能中途退出 还可能像这样写错解锁方法
    
    
            }
    

       正确而麻烦的try catch finally

            /// <summary>
            /// 加入有序队列。
            /// </summary>
            /// <param name="item">加入的项目</param>
            public void Enqueue2(TValue item)
            {
                _lock.EnterWriteLock();
    
                try
                {
                    Queue<TValue> enqueueTarget;
                    var key = _keySelector(item);
                    if (!_items.ContainsKey(key))
                    {
                        var sortValue = _sortValueSelector(item);
                        if (!_index.TryGetValue(_sortValueSelector(item), out enqueueTarget))
                        {
                            enqueueTarget = new Queue<TValue>();
                            _index.Add(sortValue, enqueueTarget);
                        }
    
                        enqueueTarget.Enqueue(item);
                        _items.Add(key, item);
                    }
                    else
                    {
                        throw new InvalidOperationException("this Item already in queue");
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                finally
                {
                    _lock.ExitWriteLock();
                
                }
    
    
            }
    
    
  • 相关阅读:
    HDFS基本原理及数据存取实战
    关于软件工程的思考06:微软解决方案框架MSF
    关于软件工程的思考05:敏捷流程
    关于软件工程的思考04:团队和流程
    关于软件工程的思考03:两人合作
    关于软件工程的思考02:软件工程师的成长
    关于软件工程的思考01:个人技术流程
    Linux31:磁盘配额与磁盘阵列简介
    Linux30:LVM和SELinux简介
    Linux29:SSH
  • 原文地址:https://www.cnblogs.com/waynebaby/p/1900998.html
Copyright © 2020-2023  润新知