对不能用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(); } }