In C #, how do you unilaterally serialize unserializable?

Often I need to serialize an object, both for logging and debugging. This is one-way serialization - I don’t need to return it later, I just need to turn the object into a string in order to write it somewhere.

Yes, yes - so you should always override the ToString method. I know it. But I often deal with objects that I did not write and cannot change. In addition, I do not want to write or update the ToString method for each class that I write.

XML serialization seems to offer the perfect solution - just flatten this object in XML. But there are so many limitations, in particular, that you cannot serialize an IDictionary, and you must have a constructor without parameters. I can get around them in my classes, but - again - I often work with other classes of people.

So, what is the solution to get the full string representation of an object? Is there something simple that I'm missing?

+43
c # serialization
Dec 19 '12 at 15:23
source share
2 answers

What about an extension method with your own logic (and maybe some reflection)?

 public static class SerializerExtension { public static String OneWaySerialize(this Object obj) { if (Object.ReferenceEquals(obj, null)) { return "NULL"; } if (obj.GetType().IsPrimitive || obj.GetType() == typeof(String)) { if (obj is String) return String.Format("\"{0}\"", obj); if (obj is Char) return String.Format("'{0}'", obj); return obj.ToString(); } StringBuilder builder = new StringBuilder(); Type objType = obj.GetType(); if (IsEnumerableType(objType)) { builder.Append("["); IEnumerator enumerator = ((IEnumerable)obj).GetEnumerator(); Boolean moreElements = enumerator.MoveNext(); while (moreElements) { builder.Append(enumerator.Current.OneWaySerialize()); moreElements = enumerator.MoveNext(); if (moreElements) { builder.Append(","); } } builder.Append("]"); } else { builder.AppendFormat("{0} {{ ", IsAnonymousType(objType) ? "new" : objType.Name); PropertyInfo[] properties = objType.GetProperties(); for (Int32 p = properties.Length; p > 0; p--) { PropertyInfo prop = properties[p-1]; String propName = prop.Name; Object propValue = prop.GetValue(obj, null); builder.AppendFormat("{0} = {1}", propName, propValue.OneWaySerialize()); if (p > 1) { builder.Append(", "); } } builder.Append(" }"); } return builder.ToString(); } // http://stackoverflow.com/a/2483054/298053 private static Boolean IsAnonymousType(Type type) { if (type == null) { return false; } return Attribute.IsDefined(type, typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), false) && type.IsGenericType && type.Name.Contains("AnonymousType") && (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$")) && (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic; } private static Boolean IsEnumerableType(Type type) { if (type == null) { return false; } foreach (Type intType in type.GetInterfaces()) { if (intType.GetInterface("IEnumerable") != null || (intType.IsGenericType && intType.GetGenericTypeDefinition() == typeof(IEnumerable<>))) { return true; } } return false; } } 

Call it like this:

 someDefinedObject.OneWaySerialize(); 

Revisisons

  • Source version
  • Updated 12.26.2012
    • IEnumerable check added (thanks aboveyou00)
    • Added anonymous type checking (and just name it "new" when exiting)
+38
Dec 19 '12 at 15:26
source share

If it's more convenient for you to serialize JSON, Json.NET is a great solution to this problem.

+14
Dec 19 '12 at 15:27
source share



All Articles