Data Model Code
0Hancock posted on 2022/02/22 16:17:34
using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
#if NewtonJson
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
#else
using System.Text.Json;
#endif
namespace AS.Core.Common
{
public static class ModelExtensions
{
public static readonly object NotExistProperty = new object();
#if !NewtonJson
private static object GetJsonElementObject(JsonElement el)
{
IDictionary<string, object> expandoObject = new ExpandoObject();
foreach (var obj in el.EnumerateObject())
{
var k = obj.Name;
var value = GetJsonElementValue(obj.Value);
expandoObject[k] = value;
}
return expandoObject;
}
private static object GetJsonElementValue(JsonElement el)
{
object val = null;
switch (el.ValueKind)
{
case JsonValueKind.Object: val = GetJsonElementObject(el); break;
case JsonValueKind.True: val = true; break;
case JsonValueKind.False: val = false; break;
case JsonValueKind.String: val = el.GetString(); break;
case JsonValueKind.Number: val = el.GetDecimal(); break;
case JsonValueKind.Array:
{
Array objArray = Array.CreateInstance(typeof(object), el.GetArrayLength());
int index = 0;
var numerator = el.EnumerateArray();
foreach (var item in numerator)
{
objArray.SetValue(GetJsonElementValue(item), index++);
}
val = objArray;
}
break;
}
return val;
}
#endif
internal static object GetValue(this object model, string name)
{
if (name.Contains("."))
{
string rName = name.Substring(0, name.IndexOf("."));
name = name.Replace(rName + ".", "");
model = GetValue(model, rName);
return GetValue(model, name);
}
if (model is IDictionary<string, object>)
{
var dicData = (IDictionary<string, object>)model;
if (dicData.ContainsKey(name))
{
object val = dicData[name];
#if !NewtonJson
if (val is JsonElement) val = GetJsonElementValue((JsonElement)val);
#endif
return val;
}
}
#if NewtonJson
else if (model is JObject)
{
var jsonData = (JObject)model;
name = ToCamelCase(name);
if (jsonData.ContainsKey(name)) return jsonData.GetValue(name).Value<dynamic>();
}
#endif
else
{
PropertyInfo prop = model.GetType().GetProperty(name);
if (prop != null) return prop.GetValue(model);
}
return NotExistProperty;
}
internal static void SetValue(this IDictionary<string, object> container, string name, object val)
{
if (name.Contains("."))
{
string rName = name.Substring(0, name.IndexOf("."));
name = name.Replace(rName + ".", "");
IDictionary<string, object> uObj = null;
if (!container.ContainsKey(rName))
{
dynamic obj = new ExpandoObject();
uObj = obj;
container.Add(rName, obj);
}
else
{
uObj = (IDictionary<string, object>)container[rName];
}
SetValue(uObj, name, val);
return;
}
name = ToCamelCase(name);
container[name] = val;
}
internal static string ToCamelCase(string s)
{
return char.ToLower(s[0]) + s.Substring(1);//.Replace("_", "");
}
private static bool IsFinalValue(this object val)
{
if (val == null) return true;
Type type = val.GetType();
if (type.IsArray) type = type.GetElementType();
if (type.IsPrimitive
|| val is decimal
|| val is string
|| val is DateTime
|| val is Enum
|| val is Guid) return true;
return false;
}
private static bool IsFinalType(this Type type)
{
Type nullableType = Nullable.GetUnderlyingType(type);
if (nullableType != null) type = nullableType;
if (type.IsPrimitive
|| typeof(decimal).IsAssignableFrom(type)
|| typeof(string).IsAssignableFrom(type)
|| typeof(DateTime).IsAssignableFrom(type)
|| typeof(Enum).IsAssignableFrom(type)
|| typeof(Guid).IsAssignableFrom(type)) return true;
return false;
}
public static dynamic ToDynamic(this object model, Func<Type, string, string> customPropName, Func<Type, object, object> customEnumValue)
{
if (model == null) return null;
if (model.IsFinalValue()) return model;
if (model is IDictionary<string, object>)
{
IDictionary<string, object> pObj = new ExpandoObject();
foreach (var o in model as IDictionary<string, object>)
{
pObj.SetValue(o.Key, o.Value.ToDynamic(customPropName, customEnumValue) as object);
}
return pObj;
}
else if (model is System.Collections.IEnumerable)
{
List<object> data = new List<object>();
System.Collections.IEnumerator enumerator = ((System.Collections.IEnumerable)model).GetEnumerator();
while (enumerator.MoveNext())
{
data.Add(enumerator.Current.ToDynamic(customPropName, customEnumValue));
}
return data.ToArray();
}
Type type = model.GetType();
IDictionary<string, object> uObj = new ExpandoObject();
PropertyInfo[] props = type.GetProperties();
foreach (var p in props)
{
if (p.CanRead)
{
object val = p.GetValue(model);
string sName = p.Name;
if (val.IsFinalValue())
{
if (val is Enum && customEnumValue != null)
{
Type enumType = val.GetType();
val = customEnumValue(enumType, val);
}
if (customPropName != null) sName = customPropName(type, sName);
uObj.SetValue(sName, val);
}
else
{
uObj.SetValue(sName, val.ToDynamic(customPropName, customEnumValue) as object);
}
}
}
return uObj;
}
public static void Generate(this object model, Func<Type, string, (string, string)> customSettings)
{
Type type = model.GetType();
PropertyInfo[] props = type.GetProperties();
Random rnd = new Random();
foreach (var p in props)
{
if (p.CanWrite)
{
object val = null;
string mockData = null, dataType = null;
(mockData, dataType) = customSettings(type, p.Name);
if (p.PropertyType.IsFinalType())
{
val = DataGenerator.GenerateValue(p.PropertyType, rnd, mockData, dataType);
}
else if (p.PropertyType.IsArray)
{
Type elType = p.PropertyType.GetElementType();
Array objArray = Array.CreateInstance(elType, rnd.Next(1, 10));
for (int i = 0; i < objArray.Length; i++)
{
object obj = null;
if (elType.IsFinalType())
{
obj = DataGenerator.GenerateValue(elType, rnd, mockData, dataType);
}
else
{
obj = Activator.CreateInstance(elType);
obj.Generate();
}
objArray.SetValue(obj, i);
}
val = objArray;
}
else if (typeof(IList).IsAssignableFrom(p.PropertyType))
{
Type elType = p.PropertyType.GenericTypeArguments[0];
var constructedListType = typeof(List<>).MakeGenericType(elType);
int cnt = rnd.Next(1, 10);
var list = (IList)Activator.CreateInstance(constructedListType);
for (int i = 0; i < cnt; i++)
{
object obj = null;
if (elType.IsFinalType())
{
obj = DataGenerator.GenerateValue(elType, rnd, mockData, dataType);
}
else
{
obj = Activator.CreateInstance(elType);
obj.Generate();
}
list.Add(obj);
}
val = list;
}
else
{
val = Activator.CreateInstance(p.PropertyType);
val.Generate(customSettings);
}
p.SetValue(model, val);
}
}
}
private static void FormSerialize(IDictionary<string, object> data, StringBuilder builder, string preKey, bool ignoreIfNull)
{
if (data == null) return;
foreach (var p in data)
{
if (p.Value is IDictionary<string, object>)
{
FormSerialize(p.Value as IDictionary<string, object>, builder, (preKey == null ? "" : preKey + ".") + WebUtility.UrlEncode(p.Key), ignoreIfNull);
}
else if(p.Value is Array)
{
Array arr = p.Value as Array;
for (int i = 0; i < arr.Length; i++)
{
var val = arr.GetValue(i);
if(val is IDictionary<string, object>)
{
FormSerialize(val as IDictionary<string, object>, builder, WebUtility.UrlEncode(p.Key) + "[" + i + "]", ignoreIfNull);
}
else
{
if (ignoreIfNull && val == null)
continue;
else
builder.Append((preKey == null ? "" : preKey + ".") + WebUtility.UrlEncode(p.Key) + "[" + i + "]" + "=" + val.UrlEncode() + "&");
}
}
}
else if(ignoreIfNull && p.Value == null) continue;
else builder.Append((preKey == null ? "" : preKey + ".") + WebUtility.UrlEncode(p.Key) + "=" + p.Value.UrlEncode() + "&");
}
}
private static string UrlEncode(this object val)
{
if (val == null) return "";
return WebUtility.UrlEncode(val.ToString());
}
public static string ToFormData(this object obj,bool ignoreIfNull = true, string preKey = null)
{
StringBuilder builder = new StringBuilder();
FormSerialize(obj.ToDynamic() as IDictionary<string, object>, builder, WebUtility.UrlEncode(preKey), ignoreIfNull);
return builder.ToString().Trim('&');
}
private static Array ToArray(this object val)
{
Array objArray = null;
if (val is Array)
{
objArray = val as Array;
}
#if NewtonJson
else if (val is JArray)
{
JArray valArray = (JArray)val;
objArray = Array.CreateInstance(typeof(object), valArray.Count);
for (int i = 0; i < valArray.Count; i++)
{
objArray.SetValue(valArray[i], i);
}
}
#endif
return objArray;
}
public static void Copy(this object model, object data, bool copiedIfNull, Func<Type, string, string> customPropName, Func<Type, object, object> customEnumValue)
{
if (data == null) return;
Type type = model.GetType();
PropertyInfo[] props = type.GetProperties();
foreach (var p in props)
{
if (p.CanWrite)
{
string sName = p.Name;
if (customPropName != null) sName = customPropName(type, sName);
object val = data.GetValue(sName);
//try to assign value
if (val == null)
{
if (copiedIfNull)
{
p.SetValue(model, null);
}
}
else if (val != NotExistProperty)
{
if (p.PropertyType.IsFinalType())
{
if (typeof(Enum).IsAssignableFrom(p.PropertyType))
{
if (customEnumValue != null) val = customEnumValue(p.PropertyType, val);
val = Enum.Parse(p.PropertyType, val.ToString());
}
p.SetValue(model, Convert.ChangeType(val, p.PropertyType));
}
else if (p.PropertyType.IsArray)
{
Type elType = p.PropertyType.GetElementType();
Array valArray = val.ToArray();
if (valArray != null)
{
Array objArray = Array.CreateInstance(elType, valArray.Length);
for (int i = 0; i < objArray.Length; i++)
{
if (elType.IsFinalType())
{
val = valArray.GetValue(i);
if (typeof(Enum).IsAssignableFrom(elType))
{
if (customEnumValue != null) val = customEnumValue(elType, val);
val = Enum.Parse(elType, val.ToString());
}
objArray.SetValue(Convert.ChangeType(val, elType), i);
}
else
{
object obj = Activator.CreateInstance(elType);
objArray.SetValue(obj, i);
obj.Copy(valArray.GetValue(i), copiedIfNull, customPropName, customEnumValue);
}
}
p.SetValue(model, objArray);
}
}
else
{
object obj = Activator.CreateInstance(p.PropertyType);
p.SetValue(model, obj);
obj.Copy(val, copiedIfNull, customPropName, customEnumValue);
}
}
}
}
}
}
}