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