/////////////////////////////////////////////////////////////////////////// // Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 // // Please see: http://www.gnu.org/licenses/gpl.html for legal details, // // rights of fair usage, the disclaimer and warranty conditions. // /////////////////////////////////////////////////////////////////////////// // Based on: Danilow @ https://stackoverflow.com/questions/23897145/memory-leak-using-streamreader-and-xmlserializer/ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; using System.Xml.Serialization; namespace wasSharpNET.Serialization { public static class XmlSerializerCache { private static readonly ReaderWriterLockSlim SerializerCacheLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); private static readonly Dictionary SerializerCache = new Dictionary(); public static XmlSerializer GetSerializer() { return GetSerializer(null); } public static XmlSerializer GetSerializer(Type[] ExtraTypes) { return GetSerializer(typeof(T), ExtraTypes); } public static XmlSerializer GetSerializer(Type MainTypeForSerialization) { return GetSerializer(MainTypeForSerialization, null); } public static XmlSerializer GetSerializer(Type MainTypeForSerialization, Type[] ExtraTypes) { var Signature = MainTypeForSerialization.FullName; if (ExtraTypes != null) Signature = ExtraTypes.Aggregate(Signature, (current, tp) => current + "-" + tp.FullName); SerializerCacheLock.EnterReadLock(); XmlSerializer XmlEventSerializer; if (SerializerCache.TryGetValue(Signature, out XmlEventSerializer)) { SerializerCacheLock.ExitReadLock(); return XmlEventSerializer; } SerializerCacheLock.ExitReadLock(); if (ExtraTypes == null) return new XmlSerializer(MainTypeForSerialization); XmlEventSerializer = new XmlSerializer(MainTypeForSerialization, ExtraTypes); SerializerCacheLock.EnterWriteLock(); SerializerCache.Add(Signature, XmlEventSerializer); SerializerCacheLock.ExitWriteLock(); return XmlEventSerializer; } public static T Deserialize(XDocument XmlData) { return Deserialize(XmlData, null); } public static T Deserialize(XDocument XmlData, Type[] ExtraTypes) { try { using (var XmlReader = XmlData.Root.CreateReader()) { return (T) GetSerializer(ExtraTypes).Deserialize(XmlReader); } } catch (Exception ex) { throw new Exception("Could not deserialize to " + typeof(T).Name, ex); } } public static T Deserialize(string XmlData) { return Deserialize(XmlData, null); } public static T Deserialize(string XmlData, Type[] ExtraTypes) { try { using (var XmlReader = XDocument.Parse(XmlData).Root.CreateReader()) { return (T) GetSerializer(ExtraTypes).Deserialize(XmlReader); } } catch (Exception ex) { throw new Exception("Could not deserialize to " + typeof(T).Name, ex); } } public static XDocument Serialize(T Object, Type[] ExtraTypes) { try { using (var memoryStream = new MemoryStream()) { using (var streamReader = new StreamReader(memoryStream)) { using (var xmlWriter = XmlWriter.Create(memoryStream, new XmlWriterSettings {Indent = true})) { var ns = new XmlSerializerNamespaces(); ns.Add(string.Empty, string.Empty); GetSerializer(ExtraTypes).Serialize(xmlWriter, Object, ns); xmlWriter.Flush(); memoryStream.Position = 0L; return XDocument.Load(streamReader, LoadOptions.None); } } } } catch (Exception ex) { throw new Exception("Could not serialize from " + typeof(T).Name + " to xml string", ex); } } public static XDocument Serialize(T Object) { return Serialize(Object, null); } public static async Task Deserialize(StreamReader streamReader) { return Deserialize(await streamReader.ReadToEndAsync(), null); } public static async Task Deserialize(Stream stream) { using (var memoryStream = new MemoryStream()) { await stream.CopyToAsync(memoryStream); memoryStream.Position = 0L; using (var streamReader = new StreamReader(memoryStream)) { return Deserialize(streamReader.ReadToEnd(), null); } } } public static void Serialize(Stream stream, T value) { Serialize(value, null).Save(stream); } public static void Serialize(StreamWriter streamWriter, T value) { Serialize(value, null).Save(streamWriter); } public static void Serialize(StringWriter stringWriter, T value) { Serialize(value, null).Save(stringWriter); } public static async Task Deserialize(TextReader reader) { return Deserialize(await reader.ReadToEndAsync(), null); } } }