Created
June 23, 2016 08:23
-
-
Save bymyslf/5d6e0b5f50bcec4c6fd24c79a0ba111b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Reflection; | |
internal class ObjectRenderer | |
{ | |
private TextWriter writer; | |
private static readonly Func<PropertyInfo, object, object> propertyGetter; | |
static ObjectRenderer() | |
{ | |
propertyGetter = OpenInstancePropertyAcessor(); | |
} | |
private ObjectRenderer(TextWriter writer) | |
{ | |
this.writer = writer; | |
} | |
private void RenderObject(object obj) | |
{ | |
if (obj == null) | |
{ | |
writer.Write("null"); | |
return; | |
} | |
if (obj is ValueType || obj is string) | |
{ | |
writer.Write(obj.ToString()); | |
return; | |
} | |
if (obj is DateTime) | |
{ | |
writer.Write(((DateTime)obj).ToShortDateString()); | |
return; | |
} | |
Array objArray = obj as Array; | |
if (objArray != null) | |
{ | |
RenderArray(objArray); | |
return; | |
} | |
// Test if we are dealing with some form of collection object | |
IEnumerable objEnumerable = obj as IEnumerable; | |
if (objEnumerable != null) | |
{ | |
// Get a collection interface if we can as its .Count property may be more | |
// performant than getting the IEnumerator object and trying to advance it. | |
ICollection objCollection = obj as ICollection; | |
if (objCollection != null && objCollection.Count == 0) | |
{ | |
writer.Write("{}"); | |
return; | |
} | |
// This is a special check to allow us to get the enumerator from the IDictionary | |
// interface as this guarantees us DictionaryEntry objects. Note that in .NET 2.0 | |
// the generic IDictionary<> interface enumerates KeyValuePair objects rather than | |
// DictionaryEntry ones. However the implementation of the plain IDictionary | |
// interface on the generic Dictionary<> still returns DictionaryEntry objects. | |
IDictionary objDictionary = obj as IDictionary; | |
if (objDictionary != null) | |
{ | |
RenderEnumerator(objDictionary.GetEnumerator()); | |
return; | |
} | |
RenderEnumerator(objEnumerable.GetEnumerator()); | |
return; | |
} | |
IEnumerator objEnumerator = obj as IEnumerator; | |
if (objEnumerator != null) | |
{ | |
RenderEnumerator(objEnumerator); | |
return; | |
} | |
if (obj is DictionaryEntry) | |
{ | |
RenderDictionaryEntry((DictionaryEntry)obj); | |
return; | |
} | |
Type objType = obj.GetType(); | |
writer.Write(objType.FullName); | |
writer.Write(":"); | |
writer.Write("{"); | |
MemberInfo[] members = objType.GetMembers(BindingFlags.Public | BindingFlags.Instance); | |
int pos = 0; | |
foreach (MemberInfo member in members) | |
{ | |
FieldInfo fieldInfo = member as FieldInfo; | |
PropertyInfo propertyInfo = member as PropertyInfo; | |
if (fieldInfo != null || propertyInfo != null) | |
{ | |
if (pos++ > 0) | |
{ | |
writer.Write(", "); | |
} | |
writer.Write(member.Name); | |
writer.Write("="); | |
object value = fieldInfo != null ? fieldInfo.GetValue(obj) : propertyGetter(propertyInfo, obj); | |
if (value != null) | |
{ | |
Type type = fieldInfo != null ? fieldInfo.FieldType : propertyInfo.PropertyType; | |
bool isReferenceType = !(type.IsValueType || type == typeof(string)); | |
if (isReferenceType) | |
{ | |
writer.Write("{"); | |
} | |
RenderObject(value); | |
if (isReferenceType) | |
{ | |
writer.Write("}"); | |
} | |
} | |
} | |
} | |
writer.Write("}"); | |
} | |
private void RenderArray(Array array) | |
{ | |
//If the array is not one dimensional | |
if (array.Rank != 1) | |
{ | |
writer.Write(array.ToString()); | |
} | |
else | |
{ | |
writer.Write(array.GetType().Name + " {"); | |
int len = array.Length; | |
if (len > 0) | |
{ | |
RenderObject(array.GetValue(0)); | |
for (int i = 1; i < len; i++) | |
{ | |
writer.Write(", "); | |
RenderObject(array.GetValue(i)); | |
} | |
} | |
writer.Write("}"); | |
} | |
} | |
private void RenderEnumerator(IEnumerator enumerator) | |
{ | |
writer.Write("{"); | |
if (enumerator != null && enumerator.MoveNext()) | |
{ | |
RenderObject(enumerator.Current); | |
while (enumerator.MoveNext()) | |
{ | |
writer.Write(", "); | |
RenderObject(enumerator.Current); | |
} | |
} | |
writer.Write("}"); | |
} | |
private void RenderDictionaryEntry(DictionaryEntry entry) | |
{ | |
RenderObject(entry.Key); | |
writer.Write("="); | |
RenderObject(entry.Value); | |
} | |
// Create open instance delegate to make reflection faster | |
// More: http://msmvps.com/blogs/jon_skeet/archive/2008/08/09/making-reflection-fly-and-exploring-delegates.aspx | |
// https://www.simple-talk.com/blogs/2010/07/27/introduction-to-open-instance-delegates/ | |
private static Func<PropertyInfo, object, object> OpenInstancePropertyAcessor() | |
{ | |
var methodInfo = typeof(PropertyInfo).GetMethod("GetValue", new Type[] { typeof(Object) }); | |
var del = Delegate.CreateDelegate(typeof(Func<PropertyInfo, object, object>), methodInfo); | |
return del as Func<PropertyInfo, object, object>; | |
} | |
internal static void Render(object element) | |
{ | |
Render(element, Console.Out); | |
} | |
internal static void Render(object element, TextWriter writer) | |
{ | |
ObjectRenderer renderer = new ObjectRenderer(writer); | |
renderer.RenderObject(element); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment