using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Collections;
namespace DemoApplication
{
public class GeneralToStringProvider
{
public static string GeneralToString(object o)
{
return GeneralToString(o, 0);
}
private static string GeneralToString(object o, int layer)
{
StringBuilder sb = new StringBuilder();
if (o == null)
{
sb.AppendLayerFormatLine(layer, "[null]");
//sb.AppendLine("[null]");
}
else
{
Type propType;
foreach (var prop in o.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
if(!(prop.CanRead))
continue;
propType = prop.PropertyType;
if (IsBasicType(propType))
{
sb.AppendLayerFormatLine(layer, "{0}: {1}", prop.Name, GetBasicPropertyValue(o, prop));
}
else if (IsDictionary(propType))
{
object dicInstance = prop.GetValue(o, null);
if (dicInstance == null)
{
sb.AppendLayerFormatLine(layer, "{0}: [null]", prop.Name);
}
else
{
sb.AppendLayerFormatLine(layer, "{0}:", prop.Name);
Type keyType, valueType;
IsDictionary(propType, out keyType, out valueType);
if (IsBasicType(keyType) && IsBasicType(valueType))
{
object objKey, objValue;
foreach (object pair in dicInstance as IEnumerable)
{
if (pair == null)
{
sb.AppendLayerFormatLine(layer + 1, "[null]");
}
else
{
objKey = pair.GetType().GetProperty("Key").GetValue(pair, null);
objValue = pair.GetType().GetProperty("Value").GetValue(pair, null);
sb.AppendLayerFormatLine(layer + 1, "[{0} -> {1}]",
objKey == null ? "[null]" : objKey.ToString(),
objValue == null ? "[null]" : objValue.ToString()
);
}
}
}
else
{
object objKey, objValue;
foreach (object pair in dicInstance as IEnumerable)
{
if (pair == null)
{
sb.AppendLayerFormatLine(layer + 1, "[null]");
}
else
{
sb.AppendLayerFormatLine(layer + 1, "[");
objKey = pair.GetType().GetProperty("Key").GetValue(pair, null);
objValue = pair.GetType().GetProperty("Value").GetValue(pair, null);
if (IsBasicType(keyType) || objKey == null)
{
sb.AppendLayerFormatLine(layer + 1, "Key: ",
objKey == null ? "[null]" : objKey.ToString()
);
}
else
{
sb.AppendLayerFormatLine(layer + 1, "Key: ");
sb.AppendLayerFormatLine(layer + 2, "[");
sb.Append(GeneralToString(objKey, layer + 3));
sb.AppendLayerFormatLine(layer + 2, "]");
}
if (IsBasicType(valueType) || objValue == null)
{
sb.AppendLayerFormatLine(layer + 1, "Value: ",
objValue == null ? "[null]" : objValue.ToString()
);
}
else
{
sb.AppendLayerFormatLine(layer + 1, "Value: ");
sb.AppendLayerFormatLine(layer + 2, "[");
sb.Append(GeneralToString(objValue, layer + 3));
sb.AppendLayerFormatLine(layer + 2, "]");
}
sb.AppendLayerFormatLine(layer + 1, "]");
}
}
}
}
}
else if (IsCollection(propType))
{
object collectionInstance = prop.GetValue(o, null);
if (collectionInstance == null)
{
sb.AppendLayerFormatLine(layer, "{0}: [null]", prop.Name);
}
else
{
sb.AppendLayerFormatLine(layer, "{0}:", prop.Name);
foreach (object item in collectionInstance as IEnumerable)
{
if (IsBasicType(item.GetType()) || item == null)
{
sb.AppendLayerFormatLine(layer + 1, "[{0}]", item == null ? "null" : item.ToString());
}
else
{
sb.AppendLayerFormatLine(layer + 1, "[");
sb.Append(GeneralToString(item, layer + 2));
sb.AppendLayerFormatLine(layer + 1, "]");
}
}
}
}
else
{
object propValue = prop.GetValue(o, null);
if (propValue == null)
{
sb.AppendLayerFormatLine(layer, "{0}: [null]", prop.Name);
}
else
{
sb.AppendLayerFormatLine(layer, "{0}:", prop.Name);
sb.AppendLayerFormatLine(layer, "[");
sb.Append(GeneralToString(propValue, layer + 1));
sb.AppendLayerFormatLine(layer, "]");
}
}
}
}
return sb.ToString();
}
private static bool IsDictionary(Type type)
{
if (type.IsGenericType)
type = type.GetGenericTypeDefinition();
if (type == typeof(Dictionary<,>))
return true;
return false;
}
/// <summary>
/// Determines whether the specified type is a generic dictionary.
/// </summary>
/// <param name="type">The type to check.</param>
/// <param name="keyType">Type of the key.</param>
/// <param name="valueType">Type of the value.</param>
/// <returns>
/// <c>true</c> if the specified type is dictionary; otherwise, <c>false</c>.
/// </returns>
private static bool IsDictionary(Type type, out Type keyType, out Type valueType)
{
keyType = typeof(object);
valueType = typeof(object);
foreach (Type interfaceType in type.GetInterfaces())
{
if (interfaceType.IsGenericType &&
interfaceType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
{
Type[] genArgs = interfaceType.GetGenericArguments();
keyType = genArgs[0];
valueType = genArgs[1];
return true;
}
}
return false;
}
private static bool IsCollection(Type type)
{
if (type == typeof(string))
return false;
if (IsArray(type))
return true;
if (type.IsGenericType)
type = type.GetGenericTypeDefinition();
if (type == typeof(List<>) || type == typeof(HashSet<>) || type == typeof(IEnumerable<>))
return true;
return false;
}
/// <summary>
/// Gets the type of the items of a collection type.
/// </summary>
/// <param name="type">The type of the collection.</param>
/// <returns>the type of the items of a collection type.</returns>
private static Type GetCollectionItemType(Type type)
{
Type itemType = typeof(object);
if (type.IsInterface && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
itemType = type.GetGenericArguments()[0];
}
else if (type.IsInterface && type == typeof(IEnumerable))
{
itemType = typeof(object);
}
else
{
foreach (Type interfaceType in type.GetInterfaces())
{
if (interfaceType.IsGenericType &&
interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
itemType = interfaceType.GetGenericArguments()[0];
}
}
}
return itemType;
}
private static string GetBasicPropertyValue(object o, PropertyInfo prop)
{
object value = prop.GetValue(o, null);
return (value == null) ? "[null]" : value.ToString();
}
/// <summary>
/// Determines whether the specified type is basic type. A basic type is one that can be wholly expressed
/// as an XML attribute. All primitive data types and type <c>string</c> and <c>DataTime</c> are basic.
/// </summary>
/// <param name="t">The type</param>
private static bool IsBasicType(Type t)
{
if (t == typeof(string) || t.IsPrimitive || t.IsEnum || t == typeof(DateTime))
return true;
else
return false;
}
/// <summary>
/// Determines whether the specified type is array.
/// </summary>
/// <param name="t">The type</param>
/// <returns>
/// <c>true</c> if the specified type is array; otherwise, <c>false</c>.
/// </returns>
private static bool IsArray(Type t)
{
return (t.BaseType == typeof(System.Array));
}
}
public static class StringBuilderExtensions
{
public static StringBuilder AppendLayerFormatLine(this StringBuilder sb, int layer, string format, params object[] args)
{
return AppendLayerFormat(sb, layer, format + Environment.NewLine, args);
}
public static StringBuilder AppendLayerFormat(this StringBuilder sb, int layer, string format, params object[] args)
{
string strToAppend = String.Format(format, args);
return sb.AppendFormat("{0}{1}", GetLayerPrefix(layer), strToAppend);
}
private static string GetLayerPrefix(int layer)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < layer; ++i)
sb.Append(" ");
return sb.ToString();
}
}
}