DataContractSerializer没有在IEnumerator上调用Dispose

时间:2016-08-01 13:15:07

标签: c# dispose datacontractserializer ienumerator

    using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadSafeEnumerable
{
   public static class Counter
   {
      public static long Alive = 0;
      public static long Dead = 0;
   }

   public class ThreadsafeEnumerator<T> : IEnumerator<T>
   {
      private readonly IEnumerator<T> _innerCollection;
      private readonly ReaderWriterLockSlim _rwLock;

      public ThreadsafeEnumerator(IEnumerator<T> innerCollection, ReaderWriterLockSlim rwLock)
      {
         _rwLock = rwLock;
         _innerCollection = innerCollection;
         rwLock.EnterReadLock();
         ++Counter.Alive;
      }

      public void Dispose()
      {
         _rwLock.ExitReadLock();
         --Counter.Alive;
         ++Counter.Dead;
      }

      public bool MoveNext()
      {
         return _innerCollection.MoveNext();
      }

      public void Reset()
      {
         _innerCollection.Reset();
      }

      public T Current { get { return _innerCollection.Current; } }

      object IEnumerator.Current { get { return Current; } }
   }

   public class ThreadSafeCollection<T> : IList<T>
   {
      internal List<T> InnerList;
      readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);

      protected ReaderWriterLockSlim RwLock
      {
         get
         {
            return _rwLock;
         }
      }
      #region "Constructors"
      protected ThreadSafeCollection()
      {
         InnerList = new List<T>();
      }

      protected ThreadSafeCollection(params T[] items)
         : this()
      {
         if (items == null)
         {
            return;
         }

         AddRange(items);
      }
      #endregion

      #region "Destructor"
      ~ThreadSafeCollection()
      {
         _rwLock.Dispose();
      }
      #endregion

      #region "Public methods"
      public void AddRange(IEnumerable<T> items)
      {
         try
         {
            _rwLock.EnterWriteLock();
            foreach (var item in items.Where(x => x != null))
            {
               InnerList.Add(item);
            }
         }
         finally
         {
            _rwLock.ExitWriteLock();
         }
      }

      #endregion

      internal void RemoveAll(Predicate<T> predicate)
      {
         try
         {
            _rwLock.EnterWriteLock();
            InnerList.RemoveAll(predicate);
         }
         finally
         {
            _rwLock.ExitWriteLock();
         }
      }



      #region "Interface methods"
      public IEnumerator<T> GetEnumerator()
      {
         _rwLock.EnterReadLock();
         try
         {
            return new ThreadsafeEnumerator<T>(InnerList.GetEnumerator(), _rwLock);
         }
         finally
         {
            _rwLock.ExitReadLock();
         }
      }

      IEnumerator IEnumerable.GetEnumerator()
      {
         return GetEnumerator();
      }

      public void Add(T item)
      {
         try
         {
            _rwLock.EnterWriteLock();
            InnerList.Add(item);
         }
         finally
         {
            _rwLock.ExitWriteLock();
         }
      }

      public void Clear()
      {
         try
         {
            _rwLock.EnterWriteLock();
            InnerList.Clear();
         }
         finally
         {
            _rwLock.ExitWriteLock();
         }
      }

      public bool Contains(T item)
      {
         try
         {
            _rwLock.EnterReadLock();
            return InnerList.Contains(item);
         }
         finally
         {
            _rwLock.ExitReadLock();
         }
      }

      public void CopyTo(T[] array, int arrayIndex)
      {
         _rwLock.EnterReadLock();
         InnerList.CopyTo(array, arrayIndex);
         _rwLock.ExitReadLock();
      }

      public bool Remove(T item)
      {
         try
         {
            _rwLock.EnterWriteLock();
            return InnerList.Remove(item);
         }
         finally
         {
            _rwLock.ExitWriteLock();
         }
      }

      public int Count
      {
         get { return InnerList.Count; }
      }

      public bool IsReadOnly
      {
         get { return ((IList<T>)InnerList).IsReadOnly; }
      }

      public int IndexOf(T item)
      {
         try
         {
            _rwLock.EnterReadLock();
            return InnerList.IndexOf(item);
         }
         finally
         {
            _rwLock.ExitReadLock();
         }
      }

      public void Insert(int index, T item)
      {
         try
         {
            _rwLock.EnterWriteLock();
            InnerList.Insert(index, item);
         }
         finally
         {
            _rwLock.ExitWriteLock();
         }
      }

      public void RemoveAt(int index)
      {
         try
         {
            _rwLock.EnterWriteLock();
            InnerList.RemoveAt(index);
         }
         finally
         {
            _rwLock.ExitWriteLock();
         }
      }

      public T this[int index]
      {
         get
         {
            try
            {
               _rwLock.EnterReadLock();
               return InnerList[index];
            }
            finally
            {
               _rwLock.ExitReadLock();
            }
         }
         set
         {
            try
            {
               _rwLock.EnterWriteLock();
               InnerList[index] = value;
            }
            finally
            {
               _rwLock.ExitWriteLock();
            }

         }
      }
      #endregion

      #region "Public override methods"
      public override bool Equals(object obj)
      {
         if (obj == null || GetType() != obj.GetType())
         {
            return false;
         }

         return this == (ThreadSafeCollection<T>)obj;
      }

      public override int GetHashCode()
      {
         try
         {
            _rwLock.EnterReadLock();
            return InnerList.Aggregate(17, (current, x) => current + current * 23 + x.GetHashCode());
         }
         finally
         {
            _rwLock.ExitReadLock();
         }
      }

      public static bool operator ==(ThreadSafeCollection<T> obj1, ThreadSafeCollection<T> obj2)
      {
         if (ReferenceEquals(obj1, obj2))
         {
            return true;
         }

         if (ReferenceEquals(obj1, null) || ReferenceEquals(obj2, null))
         {
            return false;
         }

         var match = obj1.InnerList.Count == obj2.InnerList.Count;
         if (!match)
         {
            return false;
         }

         for (var i = 0; i < obj1.InnerList.Count; i++)
         {
            match = obj1.InnerList.Any(x => x.Equals(obj2.InnerList[i]));
            if (!match)
            {
               break;
            }
         }

         return match;
      }

      public static bool operator !=(ThreadSafeCollection<T> obj1, ThreadSafeCollection<T> obj2)
      {
         return !(obj1 == obj2);
      }
      #endregion

      #region "protected methods"

      #endregion
   }

   public class MyStringCollection : ThreadSafeCollection<string>
   {

   }

   [DataContract]
   public class MyData
   {
      MyStringCollection _strings;

      [DataMember]
      public MyStringCollection Strings
      {
         get
         {
            if (_strings == null)
            {
               _strings = new MyStringCollection();
            }

            return _strings;
         }
      }

   }
   class Program
   {
      static void Main(string[] args)
      {
         MyData o1 = new MyData();
         o1.Strings.Add("R1");
         o1.Strings.Add("R2");
         o1.Strings.Add("R3");

         Console.WriteLine($"BEFORE Counter.Alive = {Counter.Alive} ");

         using (var ms = new MemoryStream())
         {
            var dcs = new DataContractSerializer(o1.GetType());
            dcs.WriteObject(ms, o1);
            var serialisedString = Encoding.UTF8.GetString(ms.ToArray());
         }

         Console.WriteLine($"AFTER Counter.Alive = {Counter.Alive} ");

         try
         {
            o1.Strings.Add("R4");
         }
         catch (Exception ex)
         {
            Console.WriteLine(ex);
         }

         Console.WriteLine("Exit.");
      }
   }
}

我正在使用DataContractSerializer来序列化集合。此集合由类ThreadSafeCollection实现为线程安全。 ThreadSafeCollection实施IList<T>。函数IEnumerator<T>.GetEnumerator()在此类中实现。这将返回ThreadSafeEnumerator类对象。 ThreadSafeEnumerator也由我实施。

问题:

ThreadsafeEnumerator中的处理功能未被调用。由于这个_rwLock的读锁(类型ReaderWriterLockSlim)没有被释放。因此,当调用Add时,我无法获得写锁定。请参阅主函数try catch中的代码,它尝试添加但失败。

0 个答案:

没有答案