Skip to content

Instantly share code, notes, and snippets.

@leniency
Created January 30, 2013 21:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save leniency/4677093 to your computer and use it in GitHub Desktop.
Save leniency/4677093 to your computer and use it in GitHub Desktop.
An XML serialization helper that includes a serializer cache when targeting heirarchies.
/// <summary>
/// Delegate for events during the serializer cache.
/// </summary>
public delegate void SerializerCacheDelegate();
/// <summary>
/// XML serialization helper
/// </summary>
public static class Xml
{
/// <summary>
/// The NewSerializer event first when the cache receives a request
/// for a serializer instance not in the cache.
/// </summary>
public static event SerializerCacheDelegate NewSerializer;
/// <summary>
/// The NewSerializer event first when the cache receives a request
/// for a serializer instance that exists in the cache.
/// </summary>
public static event SerializerCacheDelegate CacheHit;
static readonly ConcurrentDictionary<string, XmlSerializer> _serializerCache = new ConcurrentDictionary<string, XmlSerializer>();
static object _sync = new object();
static XmlSerializer GetSerializer(Type baseType, Type[] types)
{
if (baseType == null)
{
throw new ArgumentNullException("Serializer baseType cannot be null.");
}
if (types == null)
{
throw new ArgumentNullException("Serializer types cannot be null. If this can turn up null, consider the easier Serialize<T>().");
}
// Generate the key.
var b = new StringBuilder(baseType.Name);
for (int i = 0; i < types.Length; i++)
{
b.Append(':');
b.Append(types[i].Name);
}
var key = b.ToString();
// Check if the cache contains a cached serializer or not.
XmlSerializer serializer;
if (!_serializerCache.TryGetValue(key, out serializer))
{
// Lock when adding a new value.
lock (_sync)
{
serializer = new XmlSerializer(baseType, types);
_serializerCache.TryAdd(key, serializer);
if (NewSerializer != null)
{
NewSerializer();
}
}
}
else
{
if (CacheHit != null)
{
CacheHit();
}
}
return serializer;
}
/// <summary>
/// Get a list of all the cached serializer keys.
/// </summary>
/// <returns></returns>
public static IEnumerable<string> GetCache()
{
return _serializerCache.Keys.ToArray();
}
/// <summary>
/// Reset the current cache.
/// </summary>
public static void ResetCache()
{
_serializerCache.Clear();
}
/// <summary>
/// Serialize the given object into UTF-8 encoded XML
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public static string Serialize(object item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
using (var stream = new MemoryStream())
{
// This constructor is automatically cached, so no need for the
// local cache.
var serializer = new XmlSerializer(item.GetType());
serializer.Serialize(stream, item);
return Encoding.UTF8.GetString(stream.ToArray());
}
}
/// <summary>
/// Serialize the given object into UTF-8 encoded XML
/// </summary>
/// <param name="item"></param>
/// <param name="types"></param>
/// <returns></returns>
public static string Serialize(object item, Type[] types)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
if (types == null)
{
throw new ArgumentNullException("types");
}
var baseType = item.GetType().BaseType;
if (baseType == null)
{
throw new InvalidOperationException("Type does not derive from anything.");
}
if (!types.Contains(item.GetType()))
{
throw new Exception("Type of T is unknown.");
}
using (var stream = new MemoryStream())
{
// Get a cached serializer.
var serializer = GetSerializer(baseType, types);
serializer.Serialize(stream, item);
return Encoding.UTF8.GetString(stream.ToArray());
}
}
/// <summary>
/// Deserialize the given UTF-8 encoded XML string
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="xml"></param>
/// <returns></returns>
public static T Deserialize<T>(string xml)
{
using (var stream = new MemoryStream(xml.ToByteArray()))
{
// This constructor is automatically cached, so no need for the
// local cache.
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(stream);
}
}
/// <summary>
/// Deserialize the given UTF-8 encoded XML string
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="xml"></param>
/// <param name="types"></param>
/// <returns></returns>
public static T Deserialize<T>(string xml, Type[] types)
{
if (types == null)
{
throw new ArgumentNullException("types");
}
if (!types.Contains(typeof(T)))
{
throw new InvalidOperationException("Type of T is unknown.");
}
var baseType = typeof(T).BaseType;
if (baseType == null)
{
throw new InvalidOperationException("Type does not derive from anything.");
}
return (T)Deserialize(xml, baseType, types);
}
/// <summary>
/// Deserialize the given UTF-8 encoded XML string
/// </summary>
/// <param name="xml"></param>
/// <param name="baseType"></param>
/// <param name="types"></param>
/// <returns></returns>
public static object Deserialize(string xml, Type baseType, Type[] types)
{
if (baseType == null)
{
throw new ArgumentNullException("baseType");
}
if (types == null)
{
throw new ArgumentNullException("types");
}
using (var stream = new MemoryStream(xml.ToByteArray()))
{
// Get a cached serializer.
var serializer = GetSerializer(baseType, types);
return serializer.Deserialize(stream);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment