c# - DataContractSerializer not calling Dispose on 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 { { return _innercollection.current; } }        object ienumerator.current { { return current; } }    }     public class threadsafecollection<t> : ilist<t>    {       internal list<t> innerlist;       readonly readerwriterlockslim _rwlock = new readerwriterlockslim(lockrecursionpolicy.supportsrecursion);        protected readerwriterlockslim rwlock       {                   {             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);             }          }                   {             _rwlock.exitwritelock();          }       }        #endregion        internal void removeall(predicate<t> predicate)       {          try          {             _rwlock.enterwritelock();             innerlist.removeall(predicate);          }                   {             _rwlock.exitwritelock();          }       }          #region "interface methods"       public ienumerator<t> getenumerator()       {          _rwlock.enterreadlock();          try          {             return new threadsafeenumerator<t>(innerlist.getenumerator(), _rwlock);          }                   {             _rwlock.exitreadlock();          }       }        ienumerator ienumerable.getenumerator()       {          return getenumerator();       }        public void add(t item)       {          try          {             _rwlock.enterwritelock();             innerlist.add(item);          }                   {             _rwlock.exitwritelock();          }       }        public void clear()       {          try          {             _rwlock.enterwritelock();             innerlist.clear();          }                   {             _rwlock.exitwritelock();          }       }        public bool contains(t item)       {          try          {             _rwlock.enterreadlock();             return innerlist.contains(item);          }                   {             _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);          }                   {             _rwlock.exitwritelock();          }       }        public int count       {          { return innerlist.count; }       }        public bool isreadonly       {          { return ((ilist<t>)innerlist).isreadonly; }       }        public int indexof(t item)       {          try          {             _rwlock.enterreadlock();             return innerlist.indexof(item);          }                   {             _rwlock.exitreadlock();          }       }        public void insert(int index, t item)       {          try          {             _rwlock.enterwritelock();             innerlist.insert(index, item);          }                   {             _rwlock.exitwritelock();          }       }        public void removeat(int index)       {          try          {             _rwlock.enterwritelock();             innerlist.removeat(index);          }                   {             _rwlock.exitwritelock();          }       }        public t this[int index]       {                   {             try             {                _rwlock.enterreadlock();                return innerlist[index];             }                         {                _rwlock.exitreadlock();             }          }          set          {             try             {                _rwlock.enterwritelock();                innerlist[index] = value;             }                         {                _rwlock.exitwritelock();             }           }       }       #endregion        #region "public override methods"       public override bool equals(object obj)       {          if (obj == null || gettype() != obj.gettype())          {             return false;          }           return == (threadsafecollection<t>)obj;       }        public override int gethashcode()       {          try          {             _rwlock.enterreadlock();             return innerlist.aggregate(17, (current, x) => current + current * 23 + x.gethashcode());          }                   {             _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;          }           (var = 0; < 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       {                   {             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.");       }    } } 

i using datacontractserializer serialize collection. collection implemented thread safe class threadsafecollection. threadsafecollection implements ilist<t>. function ienumerator<t>.getenumerator() implemented in class. returns threadsafeenumerator class object. threadsafeenumerator implemented me.

problem:

dispose function in threadsafeenumerator not getting called. due read lock of _rwlock (type readerwriterlockslim) not getting released. due not able acquire write lock when add called. see code in main function try catch tries add fails.


Comments