Skip to content

Instantly share code, notes, and snippets.

@Varun-garg
Created June 14, 2023 07:18
Show Gist options
  • Save Varun-garg/fee5fee4bd54cd516f409e601f3a3df4 to your computer and use it in GitHub Desktop.
Save Varun-garg/fee5fee4bd54cd516f409e601f3a3df4 to your computer and use it in GitHub Desktop.
object dumper c#
using System;
using System.Collections;
using System.Linq;
using System.Reflection;
using System.Text;
public class ObjectDumper
{
private readonly int indentSize;
private readonly List<int> hashListOfFoundElements;
private readonly StringBuilder stringBuilder;
private int level;
private ObjectDumper(int indentSize)
{
this.indentSize = indentSize;
stringBuilder = new StringBuilder();
hashListOfFoundElements = new List<int>();
}
public static string Dump(object element)
{
return Dump(element, 2);
}
public static string Dump(object element, int indentSize)
{
var instance = new ObjectDumper(indentSize);
return instance.DumpElement(element);
}
private string DumpElement(object element)
{
if (element == null || element is ValueType || element is string)
{
Write(FormatValue(element));
}
else
{
var objectType = element.GetType();
if (!typeof(IEnumerable).IsAssignableFrom(objectType))
{
Write("{{{0}}}", objectType.FullName);
hashListOfFoundElements.Add(element.GetHashCode());
level++;
}
var enumerableElement = element as IEnumerable;
if (enumerableElement != null)
{
foreach (object item in enumerableElement)
{
if (item is IEnumerable && !(item is string))
{
level++;
DumpElement(item);
level--;
}
else
{
if (!AlreadyTouched(item))
{
DumpElement(item);
}
else
{
Write("{{{0}}} <-- bidirectional reference found", item.GetType().FullName);
}
}
}
}
else
{
MemberInfo[] members = element.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
foreach (var memberInfo in members)
{
var fieldInfo = memberInfo as FieldInfo;
var propertyInfo = memberInfo as PropertyInfo;
if (fieldInfo == null && propertyInfo == null)
{
continue;
}
var type = fieldInfo != null ? fieldInfo.FieldType : propertyInfo.PropertyType;
object value = fieldInfo != null
? fieldInfo.GetValue(element)
: propertyInfo.GetValue(element, null);
if (type.IsValueType || type == typeof(string))
{
Write("{0}: {1}", memberInfo.Name, FormatValue(value));
}
else
{
var isEnumerable = typeof(IEnumerable).IsAssignableFrom(type);
Write("{0}: {1}", memberInfo.Name, isEnumerable ? "..." : "{ }");
var alreadyTouched = !isEnumerable && AlreadyTouched(value);
level++;
if (!alreadyTouched)
{
DumpElement(value);
}
else
{
Write("{{{0}}} <-- bidirectional reference found", value.GetType().FullName);
}
level--;
}
}
}
if (!typeof(IEnumerable).IsAssignableFrom(objectType))
{
level--;
}
}
return stringBuilder.ToString();
}
private bool AlreadyTouched(object value)
{
if (value == null)
{
return false;
}
var hash = value.GetHashCode();
for (var i = 0; i < hashListOfFoundElements.Count; i++)
{
if (hashListOfFoundElements[i] == hash)
{
return true;
}
}
return false;
}
private void Write(string value, params object[] args)
{
var space = new string(' ', level * indentSize);
if (args != null)
{
value = string.Format(value, args);
}
stringBuilder.AppendLine(space + value);
}
private string FormatValue(object o)
{
if (o == null)
{
return "null";
}
if (o is DateTime)
{
return ((DateTime)o).ToShortDateString();
}
if (o is string)
{
return string.Format("\"{0}\"", o);
}
if (o is char && (char)o == '\0')
{
return string.Empty;
}
if (o is ValueType)
{
return o.ToString();
}
if (o is IEnumerable)
{
return o.ToString();
}
return "{ }";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment