182 lines
7.2 KiB
C#
182 lines
7.2 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Dynamic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
|
|
namespace DynamicParser {
|
|
public static class ExpandoParser {
|
|
public static ExpandoObject ToExpando(in object @object) {
|
|
var properties = @object.GetType().GetProperties();
|
|
IDictionary<string, object> expando = new ExpandoObject();
|
|
foreach (var property in properties) {
|
|
var value = GetValueOrExpandoObject(@object, property);
|
|
expando.Add(property.Name, value);
|
|
}
|
|
|
|
return (ExpandoObject)expando;
|
|
}
|
|
|
|
private static object GetValueOrExpandoObject(in object @object, in PropertyInfo property) {
|
|
var value = property.GetValue(@object);
|
|
if (value == null) return null;
|
|
|
|
var valueType = value.GetType();
|
|
if (valueType.IsValueType || value is string) return value;
|
|
|
|
if (value is IList && value.GetType().IsGenericType &&
|
|
value.GetType().GetGenericTypeDefinition().IsAssignableFrom(typeof(List<>)))
|
|
return ToExpandoCollection(value as IList);
|
|
|
|
if (value is IDictionary && value.GetType().IsGenericType &&
|
|
value.GetType().GetGenericTypeDefinition().IsAssignableFrom(typeof(Dictionary<,>)))
|
|
return ToExpandoCollection(value as IDictionary);
|
|
|
|
return ToExpando(value);
|
|
}
|
|
|
|
private static List<object> ToExpandoCollection(in IList enumerable) {
|
|
var list = new List<object>();
|
|
foreach (object obj in enumerable) {
|
|
if (obj.GetType().IsValueType || obj is string) list.Add(obj);
|
|
else list.Add(ToExpando(obj));
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
private static Dictionary<object, object> ToExpandoCollection(in IDictionary enumerable) {
|
|
var dict = new Dictionary<object, object>();
|
|
foreach (var key in enumerable.Keys) {
|
|
var value = enumerable[key];
|
|
if (value.GetType().IsValueType || value is string) dict.Add(key, value);
|
|
else dict.Add(key, ToExpando(value));
|
|
}
|
|
|
|
return dict;
|
|
}
|
|
|
|
public static void PrintDynamic(in ExpandoObject data, in string prefix = "", in Type type = null) {
|
|
var dict = new Dictionary<object, object>();
|
|
foreach (var pair in data) {
|
|
dict.Add(pair.Key, pair.Value);
|
|
}
|
|
|
|
PrintDict(dict, prefix, type);
|
|
}
|
|
|
|
private static void PrintDict(in Dictionary<object, object> data, string prefix = "", in Type type = null) {
|
|
if (type != null) {
|
|
Console.WriteLine(prefix + type);
|
|
prefix += "\t";
|
|
}
|
|
foreach (var element in data) {
|
|
Console.WriteLine($"{prefix}{element.Key}: {element.Value ?? "null"}");
|
|
if (element.Value is null) continue;
|
|
|
|
if (element.Value.GetType() == typeof(ExpandoObject)) {
|
|
PrintDynamic(element.Value as ExpandoObject, prefix + "\t");
|
|
}
|
|
|
|
if (element.Value.GetType() == typeof(List<object>)) {
|
|
var list = element.Value as List<object> ?? new List<object>();
|
|
foreach (var e in list) {
|
|
if (e.GetType() == typeof(ExpandoObject))
|
|
PrintDynamic(e as ExpandoObject, prefix + "\t", e.GetType());
|
|
else Console.WriteLine(prefix + "\t" + e);
|
|
}
|
|
}
|
|
|
|
if (element.Value.GetType() == typeof(Dictionary<object, object>)) {
|
|
PrintDict(element.Value as Dictionary<object, object>, prefix + "\t");
|
|
}
|
|
}
|
|
}
|
|
|
|
public static T ToObject<T>(in ExpandoObject @object) where T : new() {
|
|
T result = Activator.CreateInstance<T>();
|
|
var properties = result.GetType().GetProperties();
|
|
|
|
foreach (var property in properties) {
|
|
property.SetValue(result, GetValue(@object, property));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private static object ToObject(in Type type, in ExpandoObject @object) {
|
|
var result = Activator.CreateInstance(type);
|
|
var properties = type.GetProperties();
|
|
|
|
foreach (var property in properties) {
|
|
property.SetValue(result, GetValue(@object, property));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private static object GetValue(in ExpandoObject @object, in PropertyInfo property) {
|
|
var value = ((IDictionary<string, object>)@object)[property.Name];
|
|
if (value == null) return default;
|
|
|
|
var vType = value.GetType();
|
|
|
|
if (vType.IsValueType || value is string) return value;
|
|
|
|
var expandoType = typeof(ExpandoObject);
|
|
|
|
if (vType == expandoType) {
|
|
return ToObject(property.PropertyType, value as ExpandoObject);
|
|
}
|
|
|
|
if (vType == typeof(List<object>)) {
|
|
var list = value as List<object> ?? new List<object>();
|
|
var type = property.PropertyType.GenericTypeArguments[0];
|
|
var enumerableType = typeof(Enumerable);
|
|
var castMethod = enumerableType.GetMethod(nameof(Enumerable.Cast))?.MakeGenericMethod(type);
|
|
var toListMethod = enumerableType.GetMethod(nameof(Enumerable.ToList))?.MakeGenericMethod(type);
|
|
|
|
IEnumerable<object> itemsToCast;
|
|
|
|
itemsToCast = list.Select(item => {
|
|
if (item.GetType() == expandoType)
|
|
return ToObject(type, item as ExpandoObject);
|
|
return Convert.ChangeType(item, type);
|
|
});
|
|
|
|
var castedItems = castMethod.Invoke(null, new[] { itemsToCast });
|
|
|
|
return toListMethod.Invoke(null, new[] { castedItems });
|
|
}
|
|
|
|
if (vType == typeof(Dictionary<object, object>)) {
|
|
var dict = value as Dictionary<object, object> ?? new Dictionary<object, object>();
|
|
var keyType = property.PropertyType.GenericTypeArguments[0];
|
|
var valueType = property.PropertyType.GenericTypeArguments[1];
|
|
|
|
var dictType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType);
|
|
var output = Activator.CreateInstance(dictType) as IDictionary ?? new Dictionary<object, object>();
|
|
|
|
foreach (var pair in dict) {
|
|
object k;
|
|
object v;
|
|
|
|
if (pair.Key.GetType() == expandoType)
|
|
k = ToObject(keyType, pair.Key as ExpandoObject);
|
|
else k = Convert.ChangeType(pair.Key, keyType);
|
|
|
|
if (pair.Value.GetType() == expandoType)
|
|
v = ToObject(valueType, pair.Value as ExpandoObject);
|
|
else v = Convert.ChangeType(pair.Value, valueType);
|
|
|
|
output.Add(k, v);
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
return default;
|
|
}
|
|
}
|
|
} |