using System; using System.IO; using System.Collections; using System.Reflection; namespace Utilities { ////// From Microsoft's http://archive.msdn.microsoft.com/cs2008samples/ /// modified for extensibility /// public class ObjectDumper { ////// StaticWrite /// /// public static void Write(object element) { Write(element, 0); } protected static TextWriter DefaultWriter=Console.Out; ////// Static Write /// /// /// public static void Write(object element, int depth) { Write(element, depth, DefaultWriter); } ////// Static Write /// /// /// /// public static void Write(object element, int depth, TextWriter log) { var dumper = new ObjectDumper(depth) {_writer = log}; dumper.WriteObject(null, element); } private TextWriter _writer; int _pos; int _level; readonly int _depth; protected ObjectDumper(int depth) { _depth = depth; } protected ObjectDumper(int depth, TextWriter log):this(depth) { _writer = log; } ////// MethodWrite /// /// protected void WriteString(string s) { if (s != null) { _writer.Write(s); _pos += s.Length; } } protected virtual void WriteIndent() { for (int i = 0; i < _level; i++) _writer.Write(" "); } protected void WriteLine() { _writer.WriteLine(); _pos = 0; } protected virtual void WriteTab() { WriteString(" "); while (_pos % 8 != 0) WriteString(" "); } protected void DescendIfDepthAllows(Action doIfDescend) { if (_level < _depth) { _level++; doIfDescend(); _level--; } } protected virtual void WriteObject(string prefix, object element) { if (element == null || element is ValueType || element is string) { WriteIndent(); WriteString(prefix); WriteValue(element); WriteLine(); } else { var enumerableElement = element as IEnumerable; if (enumerableElement != null) { WriteEnumerable(prefix, enumerableElement); } else { WriteWithReflection(element, prefix); } } } protected virtual void WriteWithReflection(object element, string prefix) { MemberInfo[] members = element.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance); WriteIndent(); WriteString(prefix); bool propWritten = false; foreach (MemberInfo m in members) { var f = m as FieldInfo; var p = m as PropertyInfo; if (f != null || p != null) { if (propWritten) { WriteTab(); } else { propWritten = true; } WriteString(m.Name); WriteString("="); Type t = f != null ? f.FieldType : p.PropertyType; if (t.IsValueType || t == typeof(string)) { WriteValue(GetValue(element, m, f, p)); } else { WriteString(typeof (IEnumerable).IsAssignableFrom(t) ? "..." : "{ }"); } } } if (propWritten) WriteLine(); WriteReflectionChildren(element, members); } protected virtual object GetValue(object element, MemberInfo m, FieldInfo f, PropertyInfo p) { return f != null ? f.GetValue(element) : p.GetValue(element, null); } protected void WriteReflectionChildren(object element, MemberInfo[] members) { if (_level < _depth) { foreach (MemberInfo m in members) { var f = m as FieldInfo; var p = m as PropertyInfo; if (f != null || p != null) { Type t = f != null ? f.FieldType : p.PropertyType; if (!(t.IsValueType || t == typeof(string))) { object value =GetValue(element,m,f,p); if (value != null) { _level++; WriteObject(m.Name + ": ", value); _level--; } } } } } } protected virtual void WriteEnumerable(string prefix, IEnumerable enumerableElement) { foreach (object item in enumerableElement) { if (item is IEnumerable && !(item is string)) { WriteIndent(); WriteString(prefix); WriteString("..."); WriteLine(); if (_level < _depth) { _level++; WriteObject(prefix, item); _level--; } } else { WriteObject(prefix, item); } } } protected virtual void WriteValue(object o) { if (o == null) { WriteString("null"); } else if (o is DateTime) { WriteString(((DateTime)o).ToShortDateString()); } else if (o is ValueType || o is string) { WriteString(o.ToString()); } else if (o is IEnumerable) { WriteString("..."); } else { WriteString("{ }"); } } } }
Note that this code currently throws an exception if the object passed into it is a Type, for example:
var type=typeof(string); ObjectDumper.Write(type);
Throws: TargetInvocationException: Exception has been thrown by the target of an invocation. So... the refactoring commenced and the derived class that handles types, and also KeyValuePairs
using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; namespace TechnicalDebtTaskLib.Utilities { public class ObjectDumperExtended : ObjectDumper { public new static void Write(object element) { Write(element, 0); } public new static void Write(object element, int depth) { Write(element, depth, DefaultWriter); } public new static void Write(object element, int depth, TextWriter log) { var dumper = new ObjectDumperExtended(depth,log) ; dumper.WriteObject(null, element); } public static string ToDumpString(object element, int depth = 0) { using (var textWriter = new StringWriter()) { Write(element, depth, textWriter); return textWriter.ToString(); } } protected override void WriteObject(string prefix, object element) { if (element != null && element is Type ) { WriteType(prefix, element as Type); } else base.WriteObject(prefix, element); } private void WriteType(string prefix, Type type) { switch (_typeStrategy) { case TypeStrategy.Custom: WriteString(_writeTypeStrategy(prefix,type)); break; case TypeStrategy.Extended: base.WriteObject(prefix,type); break; default: WriteString(prefix + type.ToString()); break; } } protected override object GetValue(object element, MemberInfo m, FieldInfo f, PropertyInfo p) { var blackList = new[] { "DeclaringMethod", "GenericParameterAttributes", "GenericParameterPosition" }; if (element is Type && blackList.Contains(m.Name)) { return "[UnsafeToReflect]"; } return base.GetValue(element, m, f, p); } private static TypeStrategy _typeStrategy = TypeStrategy.Basic; public enum TypeStrategy { Basic=1, Custom=2, Extended=3 } private static Func<string, Type, string> _writeTypeStrategy; public static void SetTypeStrategy(Func<string,Type ,string> formatter) { if (formatter == null) _typeStrategy = TypeStrategy.Basic; else { _writeTypeStrategy = formatter; _typeStrategy = TypeStrategy.Custom; } } public static void SetTypeStrategyBasic() { _typeStrategy = TypeStrategy.Basic; _writeTypeStrategy = null; } public static void SetTypeStrategyExtended() { _typeStrategy = TypeStrategy.Extended; _writeTypeStrategy = null; } public static Func<string> WriteIndentStrategy { get; set; } protected override void WriteIndent() { if (WriteIndentStrategy != null) WriteString(WriteIndentStrategy()); else base.WriteIndent(); } public static Func<string> WriteTabStrategy { get; set; } protected override void WriteTab() { if (WriteTabStrategy != null) WriteString(WriteTabStrategy()); else base.WriteTab(); } private ObjectDumperExtended(int depth,TextWriter log) : base(depth,log){} protected override void WriteValue(object o) { if (o == null) { WriteString("null"); } else if (o is DateTime) { WriteString(((DateTime)o).ToShortDateString()); } else if (o.GetType().IsGenericType) { var baseType = o.GetType().GetGenericTypeDefinition(); if (baseType == typeof(KeyValuePair<,>)) { var argTypes = baseType.GetGenericArguments(); WriteKeyValuePair(o, argTypes[0], argTypes[1]); } } else if (o is ValueType || o is string) { WriteString(o.ToString()); } else if (o is IEnumerable) { WriteString("..."); } else { WriteString("{ }"); } } private void WriteKeyValuePair(object o, Type keyType, Type valueType) { var key = o.GetType().GetProperty("Key").GetValue(o, null); var value = o.GetType().GetProperty("Value").GetValue(o, null); WriteObject(keyType.Name + ":", key); WriteIndent(); WriteObject(valueType.Name + ":", value); } } }
No comments:
Post a Comment