mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
430 lines
18 KiB
C#
430 lines
18 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Reflection.Emit;
|
||
using System.Reflection;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
|
||
namespace Serein.Library.Utils
|
||
{
|
||
/// <summary>
|
||
/// 通过字典构造动态对象
|
||
/// </summary>
|
||
public class DynamicObjectHelper
|
||
{
|
||
// 类型缓存,键为类型的唯一名称(可以根据实际需求调整生成方式)
|
||
private static Dictionary<string, Type> typeCache = new Dictionary<string, Type>();
|
||
private static readonly AssemblyBuilder AssemblyBuilder;
|
||
private static readonly ModuleBuilder ModuleBuilder;
|
||
|
||
static DynamicObjectHelper() // 静态构造函数
|
||
{
|
||
var assemblyName = new AssemblyName("DynamicAssembly");
|
||
AssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
|
||
ModuleBuilder = AssemblyBuilder.DefineDynamicModule("MainModule");
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 获取运行时创建过的类型
|
||
/// </summary>
|
||
/// <param name="className"></param>
|
||
/// <returns></returns>
|
||
public static Type GetCacheType(string className)
|
||
{
|
||
if(typeCache.TryGetValue(className, out var type))
|
||
{
|
||
return type;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public static object Resolve(IDictionary<string, object> properties, string typeName)
|
||
{
|
||
var obj = CreateObjectWithProperties(properties, typeName);
|
||
//SetPropertyValues(obj, properties);
|
||
return obj;
|
||
}
|
||
public static bool TryResolve(IDictionary<string, object> properties, string typeName, out object result)
|
||
{
|
||
result = CreateObjectWithProperties(properties, typeName);
|
||
bool success = SetPropertyValuesWithValidation(result, properties);
|
||
return success;
|
||
// 打印赋值结果
|
||
|
||
}
|
||
// 递归方法:打印对象属性及类型
|
||
public static void PrintObjectProperties(object obj, string indent = "")
|
||
{
|
||
var objType = obj.GetType();
|
||
foreach (var prop in objType.GetProperties())
|
||
{
|
||
var value = prop.GetValue(obj);
|
||
SereinEnv.WriteLine(InfoType.INFO, $"{indent}{prop.Name} (Type: {prop.PropertyType.Name}): {value}");
|
||
|
||
if (value != null)
|
||
{
|
||
if (prop.PropertyType.IsArray) // 处理数组类型
|
||
{
|
||
var array = (Array)value;
|
||
SereinEnv.WriteLine(InfoType.INFO, $"{indent}{prop.Name} is an array with {array.Length} elements:");
|
||
for (int i = 0; i < array.Length; i++)
|
||
{
|
||
var element = array.GetValue(i);
|
||
if (element != null && element.GetType().IsClass && !(element is string))
|
||
{
|
||
SereinEnv.WriteLine(InfoType.INFO, $"{indent}\tArray[{i}] (Type: {element.GetType().Name}) contains a nested object:");
|
||
PrintObjectProperties(element, indent + "\t\t");
|
||
}
|
||
else
|
||
{
|
||
SereinEnv.WriteLine(InfoType.INFO, $"{indent}\tArray[{i}] (Type: {element?.GetType().Name}): {element}");
|
||
}
|
||
}
|
||
}
|
||
else if (value.GetType().IsClass && !(value is string)) // 处理嵌套对象
|
||
{
|
||
SereinEnv.WriteLine(InfoType.INFO, $"{indent}{prop.Name} contains a nested object:");
|
||
PrintObjectProperties(value, indent + "\t");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 创建具有属性的类型
|
||
/// </summary>
|
||
/// <param name="properties">成员属性名称及类型</param>
|
||
/// <param name="typeName">类型名称</param>
|
||
/// <param name="isOverlay">是否覆盖</param>
|
||
/// <returns></returns>
|
||
/// <exception cref="Exception"></exception>
|
||
public static Type CreateTypeWithProperties(IDictionary<string, Type> properties, string typeName, bool isOverlay = false)
|
||
{
|
||
// 如果类型已经缓存,且没有显示指定需要覆盖,直接返回缓存的类型
|
||
if (typeCache.ContainsKey(typeName) && !isOverlay)
|
||
{
|
||
return typeCache[typeName];
|
||
}
|
||
|
||
// 定义动态程序集和模块
|
||
/*var assemblyName = new AssemblyName("DynamicAssembly");
|
||
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
|
||
var moduleBuilder = AssemblyBuilder.DefineDynamicModule("MainModule");
|
||
*/
|
||
// 定义动态类型
|
||
var typeBuilder = ModuleBuilder.DefineType(typeName, TypeAttributes.Public);
|
||
|
||
// 为每个属性名和值添加相应的属性到动态类型中
|
||
foreach (var kvp in properties)
|
||
{
|
||
string propName = kvp.Key;
|
||
object propValue = kvp.Value;
|
||
Type propType;
|
||
|
||
if (propValue is IList<Dictionary<string, Type>>) // 处理数组类型
|
||
{
|
||
var nestedPropValue = (propValue as IList<Dictionary<string, Type>>)[0];
|
||
var nestedType = CreateTypeWithProperties(nestedPropValue, $"{propName}Element");
|
||
propType = nestedType.GetType().MakeArrayType(); // 创建数组类型
|
||
}
|
||
else if (propValue is Dictionary<string, Type> nestedProperties)
|
||
{
|
||
// 如果值是嵌套的字典,递归创建嵌套类型
|
||
propType = CreateTypeWithProperties(nestedProperties, $"{typeName}_{propName}").GetType();
|
||
}
|
||
else if (propValue is Type type)
|
||
{
|
||
// 如果是普通类型,使用值的类型
|
||
propType = type ?? typeof(object);
|
||
}
|
||
else
|
||
{
|
||
throw new Exception($"无法解析的类型:{propValue}");
|
||
}
|
||
|
||
// 定义私有字段和公共属性
|
||
var fieldBuilder = typeBuilder.DefineField("_" + propName, propType, FieldAttributes.Private);
|
||
var propertyBuilder = typeBuilder.DefineProperty(propName, PropertyAttributes.HasDefault, propType, null);
|
||
|
||
// 定义 getter 方法
|
||
var getMethodBuilder = typeBuilder.DefineMethod(
|
||
"get_" + propName,
|
||
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
|
||
propType,
|
||
Type.EmptyTypes);
|
||
|
||
var getIL = getMethodBuilder.GetILGenerator();
|
||
getIL.Emit(OpCodes.Ldarg_0);
|
||
getIL.Emit(OpCodes.Ldfld, fieldBuilder);
|
||
getIL.Emit(OpCodes.Ret);
|
||
|
||
// 定义 setter 方法
|
||
var setMethodBuilder = typeBuilder.DefineMethod(
|
||
"set_" + propName,
|
||
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
|
||
null,
|
||
new Type[] { propType });
|
||
|
||
var setIL = setMethodBuilder.GetILGenerator();
|
||
setIL.Emit(OpCodes.Ldarg_0);
|
||
setIL.Emit(OpCodes.Ldarg_1);
|
||
setIL.Emit(OpCodes.Stfld, fieldBuilder);
|
||
setIL.Emit(OpCodes.Ret);
|
||
|
||
// 将 getter 和 setter 方法添加到属性
|
||
propertyBuilder.SetGetMethod(getMethodBuilder);
|
||
propertyBuilder.SetSetMethod(setMethodBuilder);
|
||
}
|
||
|
||
// 创建类型并缓存
|
||
var dynamicType = typeBuilder.CreateType();
|
||
typeCache[typeName] = dynamicType;
|
||
|
||
// 创建对象实例
|
||
return dynamicType;
|
||
}
|
||
|
||
|
||
|
||
#region 动态创建对象并赋值
|
||
|
||
// 方法 1: 创建动态类型及其对象实例
|
||
public static object CreateObjectWithProperties(IDictionary<string, object> properties, string typeName)
|
||
{
|
||
// 如果类型已经缓存,直接返回缓存的类型
|
||
if (typeCache.ContainsKey(typeName))
|
||
{
|
||
return Activator.CreateInstance(typeCache[typeName]);
|
||
}
|
||
|
||
// 定义动态程序集和模块
|
||
var assemblyName = new AssemblyName("DynamicAssembly");
|
||
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
|
||
var moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
|
||
|
||
// 定义动态类型
|
||
var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public);
|
||
|
||
// 为每个属性名和值添加相应的属性到动态类型中
|
||
foreach (var kvp in properties)
|
||
{
|
||
string propName = kvp.Key;
|
||
object propValue = kvp.Value;
|
||
Type propType;
|
||
|
||
if (propValue is IList<Dictionary<string, object>>) // 处理数组类型
|
||
{
|
||
var nestedPropValue = (propValue as IList<Dictionary<string, object>>)[0];
|
||
var nestedType = CreateObjectWithProperties(nestedPropValue, $"{propName}Element");
|
||
propType = nestedType.GetType().MakeArrayType(); // 创建数组类型
|
||
}
|
||
else if (propValue is Dictionary<string, object> nestedProperties)
|
||
{
|
||
// 如果值是嵌套的字典,递归创建嵌套类型
|
||
propType = CreateObjectWithProperties(nestedProperties, $"{typeName}_{propName}").GetType();
|
||
}
|
||
else
|
||
{
|
||
// 如果是普通类型,使用值的类型
|
||
propType = propValue?.GetType() ?? typeof(object);
|
||
}
|
||
|
||
// 定义私有字段和公共属性
|
||
var fieldBuilder = typeBuilder.DefineField("_" + propName, propType, FieldAttributes.Private);
|
||
var propertyBuilder = typeBuilder.DefineProperty(propName, PropertyAttributes.HasDefault, propType, null);
|
||
|
||
// 定义 getter 方法
|
||
var getMethodBuilder = typeBuilder.DefineMethod(
|
||
"get_" + propName,
|
||
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
|
||
propType,
|
||
Type.EmptyTypes);
|
||
|
||
var getIL = getMethodBuilder.GetILGenerator();
|
||
getIL.Emit(OpCodes.Ldarg_0);
|
||
getIL.Emit(OpCodes.Ldfld, fieldBuilder);
|
||
getIL.Emit(OpCodes.Ret);
|
||
|
||
// 定义 setter 方法
|
||
var setMethodBuilder = typeBuilder.DefineMethod(
|
||
"set_" + propName,
|
||
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
|
||
null,
|
||
new Type[] { propType });
|
||
|
||
var setIL = setMethodBuilder.GetILGenerator();
|
||
setIL.Emit(OpCodes.Ldarg_0);
|
||
setIL.Emit(OpCodes.Ldarg_1);
|
||
setIL.Emit(OpCodes.Stfld, fieldBuilder);
|
||
setIL.Emit(OpCodes.Ret);
|
||
|
||
// 将 getter 和 setter 方法添加到属性
|
||
propertyBuilder.SetGetMethod(getMethodBuilder);
|
||
propertyBuilder.SetSetMethod(setMethodBuilder);
|
||
}
|
||
|
||
// 创建类型并缓存
|
||
var dynamicType = typeBuilder.CreateType();
|
||
typeCache[typeName] = dynamicType;
|
||
|
||
// 创建对象实例
|
||
return Activator.CreateInstance(dynamicType);
|
||
}
|
||
|
||
// 方法 2: 递归设置对象的属性值
|
||
public static void SetPropertyValues(object obj, Dictionary<string, object> properties)
|
||
{
|
||
var objType = obj.GetType();
|
||
|
||
foreach (var kvp in properties)
|
||
{
|
||
var propInfo = objType.GetProperty(kvp.Key);
|
||
object value = kvp.Value;
|
||
|
||
// 如果值是嵌套的字典类型,递归处理嵌套对象
|
||
if (value is Dictionary<string, object> nestedProperties)
|
||
{
|
||
// 创建嵌套对象
|
||
var nestedObj = Activator.CreateInstance(propInfo.PropertyType);
|
||
|
||
// 递归设置嵌套对象的值
|
||
SetPropertyValues(nestedObj, nestedProperties);
|
||
|
||
// 将嵌套对象赋值给属性
|
||
propInfo.SetValue(obj, nestedObj);
|
||
}
|
||
else
|
||
{
|
||
// 直接赋值给属性
|
||
propInfo.SetValue(obj, value);
|
||
}
|
||
}
|
||
}
|
||
// 方法 2: 递归设置对象的属性值(带验证)
|
||
|
||
public static bool SetPropertyValuesWithValidation(object obj, IDictionary<string, object> properties)
|
||
{
|
||
var objType = obj.GetType();
|
||
bool allSuccessful = true; // 标记是否所有属性赋值成功
|
||
|
||
foreach (var kvp in properties)
|
||
{
|
||
var propName = kvp.Key;
|
||
var propValue = kvp.Value;
|
||
|
||
var propInfo = objType.GetProperty(propName);
|
||
|
||
if (propInfo == null)
|
||
{
|
||
// 属性不存在,打印警告并标记失败
|
||
SereinEnv.WriteLine(InfoType.WARN, $"属性 '{propName}' 不存在于类型 '{objType.Name}' 中,跳过赋值。");
|
||
allSuccessful = false;
|
||
continue;
|
||
}
|
||
|
||
// 检查属性类型是否与要赋的值兼容
|
||
var targetType = propInfo.PropertyType;
|
||
if (!IsCompatibleType(targetType, propValue))
|
||
{
|
||
// 如果类型不兼容,打印错误并标记失败
|
||
SereinEnv.WriteLine(InfoType.ERROR, $"无法将类型 '{propValue?.GetType().Name}' 赋值给属性 '{propName}' (Type: {targetType.Name}),跳过赋值。");
|
||
allSuccessful = false;
|
||
continue;
|
||
}
|
||
|
||
try
|
||
{
|
||
// 如果值是一个嵌套对象,递归赋值
|
||
if (propValue is Dictionary<string, object> nestedProperties)
|
||
{
|
||
var nestedObj = Activator.CreateInstance(propInfo.PropertyType);
|
||
if (nestedObj != null && SetPropertyValuesWithValidation(nestedObj, nestedProperties))
|
||
{
|
||
propInfo.SetValue(obj, nestedObj);
|
||
}
|
||
else
|
||
{
|
||
allSuccessful = false; // 嵌套赋值失败
|
||
}
|
||
}
|
||
else if (propValue is IList<Dictionary<string, object>> list) // 处理列表
|
||
{
|
||
// 获取目标类型的数组元素类型
|
||
var elementType = propInfo.PropertyType.GetElementType();
|
||
if (elementType != null)
|
||
{
|
||
var array = Array.CreateInstance(elementType, list.Count);
|
||
|
||
for (int i = 0; i < list.Count; i++)
|
||
{
|
||
var item = Activator.CreateInstance(elementType);
|
||
if (item != null && SetPropertyValuesWithValidation(item, list[i]))
|
||
{
|
||
array.SetValue(item, i);
|
||
}
|
||
else
|
||
{
|
||
allSuccessful = false; // 赋值失败
|
||
}
|
||
}
|
||
propInfo.SetValue(obj, array);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 直接赋值
|
||
propInfo.SetValue(obj, propValue);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
SereinEnv.WriteLine(InfoType.ERROR, $"为属性 '{propName}' 赋值时发生异常:{ex.Message}");
|
||
allSuccessful = false;
|
||
}
|
||
}
|
||
|
||
return allSuccessful;
|
||
}
|
||
|
||
// 检查类型兼容性的方法(支持嵌套类型)
|
||
static bool IsCompatibleType(Type targetType, object value)
|
||
{
|
||
if (value == null)
|
||
{
|
||
// 如果值为null,且目标类型是引用类型或者可空类型,则兼容
|
||
return !targetType.IsValueType || Nullable.GetUnderlyingType(targetType) != null;
|
||
}
|
||
|
||
// 检查值的类型是否与目标类型相同,或是否可以转换为目标类型
|
||
if (targetType.IsAssignableFrom(value.GetType()))
|
||
{
|
||
return true;
|
||
}
|
||
|
||
// 处理数组类型
|
||
if (targetType.IsArray)
|
||
{
|
||
// 检查数组的元素类型与值的类型兼容
|
||
var elementType = targetType.GetElementType();
|
||
return value is IList<Dictionary<string, object>>; // 假设值是一个列表,具体处理逻辑在赋值时
|
||
}
|
||
|
||
// 处理嵌套类型的情况
|
||
if (value is Dictionary<string, object> && targetType.IsClass && !targetType.IsPrimitive)
|
||
{
|
||
// 如果目标类型是一个复杂对象,并且值是一个字典,可能是嵌套对象
|
||
return true; // 假设可以递归处理嵌套对象
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
#endregion
|
||
|
||
}
|
||
}
|