diff --git a/src/CloudGaming/Api/CloudGaming.Api/Controllers/AppController.cs b/src/CloudGaming/Api/CloudGaming.Api/Controllers/AppController.cs index 514ed7d..907168e 100644 --- a/src/CloudGaming/Api/CloudGaming.Api/Controllers/AppController.cs +++ b/src/CloudGaming/Api/CloudGaming.Api/Controllers/AppController.cs @@ -1,4 +1,5 @@ using CloudGaming.Api.Base; +using CloudGaming.Code.Config; using CloudGaming.DtoModel; using CloudGaming.GameModel.Db.Db_Ext; @@ -25,19 +26,11 @@ namespace CloudGaming.Api.Controllers [HttpGet] public async Task GetAppConfigAsync() { - AppConfigDto appConfigDto = new AppConfigDto(); - appConfigDto.AppConfigExtend = new AppConfigExtend(); - return appConfigDto; + AppConfigBLL appConfigBLL = new AppConfigBLL(ServiceProvider); + var appConfig = await appConfigBLL.GetAppConfig(); + return appConfig; } - /// - /// - /// - /// - [HttpGet] - public async Task> GetConfig1() - { - return new HuanMeng.DotNetCore.Base.BaseResponse(ResonseCode.Success, "成功", new T_App_Config() { BossId = "aa" }); - } + } } diff --git a/src/CloudGaming/Api/CloudGaming.Api/Program.cs b/src/CloudGaming/Api/CloudGaming.Api/Program.cs index 2a2ff27..d95e4d1 100644 --- a/src/CloudGaming/Api/CloudGaming.Api/Program.cs +++ b/src/CloudGaming/Api/CloudGaming.Api/Program.cs @@ -16,6 +16,7 @@ using CloudGaming.Code.AppExtend.JsonConverHelper.JsonConverterUtil; using CloudGaming.Code.AppExtend.JsonConverHelper; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.Extensions.Options; +using CloudGaming.GameModel.Db.Db_Ext; var builder = WebApplication.CreateBuilder(args); #region 日志 // Add services to the container. @@ -110,6 +111,21 @@ builder.Services.AddSwaggerGen(c => #endregion +#region automap +var mapperDomain = AppDomain.CurrentDomain.GetAssemblies().Where(it => it.FullName.Contains("HuanMeng") || it.FullName.Contains("CloudGaming.")).ToList(); +Type type = typeof(T_App_Config); +if (type != null) +{ + Assembly assembly = Assembly.GetAssembly(type); + if (!mapperDomain.Any(it => it.FullName == assembly.FullName)) + { + mapperDomain.Add(assembly); + } +} + +builder.Services.AddAutoMapper(mapperDomain); +#endregion + builder.AddAppConfigClient(); //添加jwt验证 builder.AddJwtConfig(); diff --git a/src/CloudGaming/CloudGaming.sln b/src/CloudGaming/CloudGaming.sln index ae7e883..5752d53 100644 --- a/src/CloudGaming/CloudGaming.sln +++ b/src/CloudGaming/CloudGaming.sln @@ -28,11 +28,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CloudGaming.Model", "Model\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CloudGaming.Code", "Code\CloudGaming.Code\CloudGaming.Code.csproj", "{5F851D79-E435-4D16-974A-6D5E3A3269A7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudGaming.CreateDataBase", "Console\CloudGaming.CreateDataBase\CloudGaming.CreateDataBase.csproj", "{393ED915-3F88-4F84-AE2A-5C95F8867F16}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CloudGaming.CreateDataBase", "Console\CloudGaming.CreateDataBase\CloudGaming.CreateDataBase.csproj", "{393ED915-3F88-4F84-AE2A-5C95F8867F16}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudGaming.GameModel", "Model\CloudGaming.GameModel\CloudGaming.GameModel.csproj", "{1120C146-6B83-4E4E-8A39-BD09466C7E1B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CloudGaming.GameModel", "Model\CloudGaming.GameModel\CloudGaming.GameModel.csproj", "{1120C146-6B83-4E4E-8A39-BD09466C7E1B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudGaming.DtoModel", "Model\CloudGaming.DtoModel\CloudGaming.DtoModel.csproj", "{96CD0865-0AD5-41B3-89A2-374FF17CDD16}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CloudGaming.DtoModel", "Model\CloudGaming.DtoModel\CloudGaming.DtoModel.csproj", "{96CD0865-0AD5-41B3-89A2-374FF17CDD16}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudGaming.Test", "Console\CloudGaming.Test\CloudGaming.Test.csproj", "{830841B9-E013-4FD5-8D31-D85545870C1C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -68,6 +70,10 @@ Global {96CD0865-0AD5-41B3-89A2-374FF17CDD16}.Debug|Any CPU.Build.0 = Debug|Any CPU {96CD0865-0AD5-41B3-89A2-374FF17CDD16}.Release|Any CPU.ActiveCfg = Release|Any CPU {96CD0865-0AD5-41B3-89A2-374FF17CDD16}.Release|Any CPU.Build.0 = Release|Any CPU + {830841B9-E013-4FD5-8D31-D85545870C1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {830841B9-E013-4FD5-8D31-D85545870C1C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {830841B9-E013-4FD5-8D31-D85545870C1C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {830841B9-E013-4FD5-8D31-D85545870C1C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -80,6 +86,7 @@ Global {393ED915-3F88-4F84-AE2A-5C95F8867F16} = {9F7EF36C-17BB-4F93-927E-F462FE3C9337} {1120C146-6B83-4E4E-8A39-BD09466C7E1B} = {A3F00FB0-49D6-48B1-99D9-4619634DF8D9} {96CD0865-0AD5-41B3-89A2-374FF17CDD16} = {A3F00FB0-49D6-48B1-99D9-4619634DF8D9} + {830841B9-E013-4FD5-8D31-D85545870C1C} = {9F7EF36C-17BB-4F93-927E-F462FE3C9337} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {1D299D92-FA27-47A0-8D78-43D1FAFE7628} diff --git a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppRequestConfig.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppRequestConfig.cs new file mode 100644 index 0000000..2394559 --- /dev/null +++ b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppRequestConfig.cs @@ -0,0 +1,123 @@ +using Microsoft.AspNetCore.Http; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.Code.AppExtend +{ + /// + /// app 请求信息 + /// + public class AppRequestConfig(HttpRequest httpRequest) + { + private string channel { get; set; } + /// + /// 渠道 + /// + public string Channel + { + get + { + if (string.IsNullOrEmpty(channel)) + { + if (!httpRequest.Headers.TryGetValue("Channel", out var _channel)) + { + _channel = "27001"; + } + channel = _channel; + } + return channel; + } + } + + private string platform; + + /// + /// 平台 + /// + public string Platform + { + get + { + if (string.IsNullOrEmpty(platform)) + { + if (!httpRequest.Headers.TryGetValue("Platform", out var _platform)) + { + _platform = "android"; + } + platform = _platform; + } + return platform; + } + } + + private string version; + /// + /// 版本 + /// + public string Version + { + get + { + if (string.IsNullOrEmpty(version)) + { + if (!httpRequest.Headers.TryGetValue("Version", out var _version)) + { + _version = "1.0.0"; + } + version = _version; + } + return version; + } + } + + public int versionNum; + public int VersionNum + { + get + { + if (versionNum == 0) + { + var str = Version.Replace(".", ""); + if (!int.TryParse(str, out versionNum)) + { + versionNum = 100; + } + } + return versionNum; + } + } + private string language; + /// + /// 语言 + /// + public string Language + { + get + { + if (string.IsNullOrEmpty(language)) + { + if (!httpRequest.Headers.TryGetValue("Version", out var _language)) + { + _language = "1.0.0"; + } + language = _language; + } + return language; + } + } + + /// + /// 地区 + /// + public string Continent { get; set; } + + /// + /// 国家 + /// + public string CountryName { get; set; } + } +} diff --git a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CloudGamingBase.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CloudGamingBase.cs index 439e2b4..1e9ba96 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CloudGamingBase.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CloudGamingBase.cs @@ -73,7 +73,7 @@ namespace CloudGaming.Code.AppExtend { if (_appConfig == null) { - _appConfig = _serviceProvider.GetService(); + _appConfig = _serviceProvider.GetRequiredService(); } return _appConfig; } @@ -187,5 +187,22 @@ namespace CloudGaming.Code.AppExtend } } #endregion + #region app配置 + private AppRequestConfig appRequestInfo; + /// + /// app请求配置 + /// + public AppRequestConfig AppRequestInfo + { + get + { + if (appRequestInfo == null) + { + appRequestInfo = new AppRequestConfig(HttpContextAccessor?.HttpContext?.Request); + } + return appRequestInfo; + } + } + #endregion } } diff --git a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CustomResultFilter.cs b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CustomResultFilter.cs index b7070e8..63c3c34 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CustomResultFilter.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/AppExtend/CustomResultFilter.cs @@ -1,4 +1,6 @@ using HuanMeng.DotNetCore.AttributeExtend; +using HuanMeng.DotNetCore.Base; +using HuanMeng.DotNetCore.Utility; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -28,29 +30,41 @@ namespace CloudGaming.Code.AppExtend var path = httpContext.Request.Path.Value ?? ""; // 获取当前用户的信息 var user = httpContext.User.Identity.IsAuthenticated ? httpContext.User.Identity.Name : "Anonymous"; - - // 获取请求头中的某个信息(例如语言信息) - var language = httpContext.Request.Headers["Accept-Language"].ToString(); - + //Dictionary keyValuePairs = new Dictionary(); if (context.Result is ObjectResult objectResult && objectResult.Value != null) { if (IsPrimitiveOrString(objectResult.Value.GetType())) { } - FindImagesAttributes(objectResult.Value); - // var responseObject = objectResult.Value; - // var membersWithImagesAttribute = responseObject.GetType() - //.GetMembers(BindingFlags.Public | BindingFlags.Instance) - //.Where(m => m.GetCustomAttribute() != null); - // foreach (var member in membersWithImagesAttribute) - // { - // var imagesAttribute = member.GetCustomAttribute(); - // Console.WriteLine($"带有 [Images] 特性的成员:{member.Name}"); - // Console.WriteLine($"FieldName 属性值:{imagesAttribute?.FieldName}"); - // } - // 递归处理返回对象的所有属性并打印路径 - ProcessObjectProperties(objectResult.Value, user, language, path); + + var dic = objectResult.Value.ToDictionary(); + //objectResult.Value = dic; + var t = objectResult.Value.GetType(); + if (!t.FullName.Contains("HuanMeng.DotNetCore.Base.BaseResponse")) + { + BaseResponse> baseResponse = new BaseResponse>(ResonseCode.Success, "", dic); + objectResult.Value = baseResponse; + } + else + { + objectResult.Value = dic; + } + //objectResult.Value.to + + //FindImagesAttributes(objectResult.Value); + //// var responseObject = objectResult.Value; + //// var membersWithImagesAttribute = responseObject.GetType() + ////.GetMembers(BindingFlags.Public | BindingFlags.Instance) + ////.Where(m => m.GetCustomAttribute() != null); + //// foreach (var member in membersWithImagesAttribute) + //// { + //// var imagesAttribute = member.GetCustomAttribute(); + //// Console.WriteLine($"带有 [Images] 特性的成员:{member.Name}"); + //// Console.WriteLine($"FieldName 属性值:{imagesAttribute?.FieldName}"); + //// } + //// 递归处理返回对象的所有属性并打印路径 + //ProcessObjectProperties(objectResult.Value, user, language, path); } } diff --git a/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLL.cs b/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLL.cs new file mode 100644 index 0000000..7cbc5e7 --- /dev/null +++ b/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLL.cs @@ -0,0 +1,36 @@ +using CloudGaming.DtoModel; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.Code.Config +{ + /// + /// + /// + public class AppConfigBLL : CloudGamingBase + { + public AppConfigBLL(IServiceProvider serviceProvider) : base(serviceProvider) + { + } + + /// + /// 获取app启动配置 + /// + /// + public async Task GetAppConfig() + { + var list = Cache.AppConfigList.Where(it => it.IsShow).ToList(); + var x = AppRequestInfo.versionNum; + AppConfigDto appConfigDto = new AppConfigDto() + { + IsAuthRealName = true + }; + appConfigDto.IsChecking = list.GetAppIsChecking(AppRequestInfo); + return appConfigDto; + } + } +} diff --git a/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLLExtend.cs b/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLLExtend.cs new file mode 100644 index 0000000..6aa8904 --- /dev/null +++ b/src/CloudGaming/Code/CloudGaming.Code/Config/AppConfigBLLExtend.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.Code.Config; + +/// +/// AppConfig扩展 +/// +public static class AppConfigBLLExtend +{ + + /// + /// 获取app是否在审核中 + /// + /// + /// + /// + public static bool GetAppIsChecking(this List app_Configs, AppRequestConfig appRequestInfo) + { + var config = GetAppConfig(app_Configs, 7, 1, appRequestInfo); + if (config == null || string.IsNullOrEmpty(config.ConfigValue)) + { + return false; + } + var version = config.ConfigValue.Replace(".", ""); + if (!int.TryParse(version, out int versionNum)) + { + return false; + } + if (appRequestInfo.VersionNum >= versionNum) + { + return true; + } + return false; + } + + /// + /// + /// + /// + /// + /// + /// + /// + public static T_App_Config GetAppConfig(this List app_Configs, int cfgType, int cfgId, AppRequestConfig appRequestInfo) + { + var list = GetAppCfgList(app_Configs, cfgType, cfgId, appRequestInfo.Channel, appRequestInfo.Platform, appRequestInfo.Continent, appRequestInfo.CountryName); + return list.FirstOrDefault(); + } + + /// + /// + /// + /// + /// + /// + /// + /// + public static List GetAppCfgList(this List app_Configs, int cfgType, int cfgId, AppRequestConfig appRequestInfo) + { + return GetAppCfgList(app_Configs, cfgType, cfgId, appRequestInfo.Channel, appRequestInfo.Platform, appRequestInfo.Continent, appRequestInfo.CountryName); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static List GetAppCfgList(this List app_Configs, int cfgType, int cfgId, string bossId, string plat = "", string continent = "", string countryName = "") + { + //有很多老配置,没有appid的参与 + var lst = app_Configs.Where(it => it.ConfigType == cfgType && it.ConfigId == cfgId).ToList(); + + #region 计算地区、国家 + if (!string.IsNullOrEmpty(continent)) + { + var tempList = lst.Where(it => !string.IsNullOrEmpty(it.Continent) && (it.Continent + ",").Contains(continent + ",")).ToList(); + if (tempList == null || tempList.Count == 0) + { + tempList = lst.Where(it => string.IsNullOrEmpty(it.Continent)).ToList(); + } + lst = tempList; + } + else + { + lst = lst.Where(it => string.IsNullOrEmpty(it.Continent)).ToList(); + } + + + if (!string.IsNullOrEmpty(countryName)) + { + var tempList = lst.Where(it => !string.IsNullOrEmpty(it.CountryName) && (it.CountryName + ",").Contains(countryName + ",")).ToList(); + if (tempList == null || tempList.Count == 0) + { + tempList = lst.Where(it => string.IsNullOrEmpty(it.CountryName)).ToList(); + } + lst = tempList; + } + else + { + lst = lst.Where(it => string.IsNullOrEmpty(it.CountryName)).ToList(); + } + #endregion + + #region 计算平台 + + if (!string.IsNullOrEmpty(plat)) + { + var tempList = lst.Where(a => a.Plat != null && a.Plat == plat).ToList(); + if (tempList == null || tempList.Count == 0) + { + tempList = lst.Where(a => a.Plat == null || string.IsNullOrEmpty(a.Plat)).ToList(); + } + lst = tempList; + } + else + { + lst = lst.Where(a => a.Plat == null || string.IsNullOrEmpty(a.Plat)).ToList(); + } + #endregion + #region 计算渠道号 + if (!string.IsNullOrEmpty(bossId)) + { + + + var lsts = lst.Where(a => a.BossId != null && (a.BossId == bossId || a.BossId.Contains(bossId))).ToList(); + if (lsts == null || lsts.Count == 0) + { + lsts = lst.Where(it => it.BossId == null || string.IsNullOrEmpty(it.BossId)).ToList(); + } + lst = lsts; + + } + else + { + lst = lst.Where(it => it.BossId == null || string.IsNullOrEmpty(it.BossId)).ToList(); + } + #endregion + + return lst; + } + +} diff --git a/src/CloudGaming/Console/CloudGaming.Test/CloudGaming.Test.csproj b/src/CloudGaming/Console/CloudGaming.Test/CloudGaming.Test.csproj new file mode 100644 index 0000000..76e5590 --- /dev/null +++ b/src/CloudGaming/Console/CloudGaming.Test/CloudGaming.Test.csproj @@ -0,0 +1,18 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + diff --git a/src/CloudGaming/Console/CloudGaming.Test/ObjectExtensions.cs b/src/CloudGaming/Console/CloudGaming.Test/ObjectExtensions.cs new file mode 100644 index 0000000..3beac1d --- /dev/null +++ b/src/CloudGaming/Console/CloudGaming.Test/ObjectExtensions.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +namespace CloudGaming.Test; + + + +public static class ObjectExtensions +{ + private static readonly ConcurrentDictionary PropertyCache = new(); + private static readonly ConcurrentDictionary FieldCache = new(); + + public static Dictionary ToDictionary(this object obj, int maxDepth = 3) + { + return ToDictionaryRecursive(obj, maxDepth); + } + + private static Dictionary ToDictionaryRecursive(object obj, int depth) + { + if (obj == null || depth < 0) + return null; + + var dictionary = new Dictionary(); + var type = obj.GetType(); + + var properties = PropertyCache.GetOrAdd(type, t => t.GetProperties(BindingFlags.Public | BindingFlags.Instance)); + foreach (var property in properties) + { + var value = property.GetValue(obj); + dictionary[property.Name] = ConvertValue(value, depth - 1); + } + + var fields = FieldCache.GetOrAdd(type, t => t.GetFields(BindingFlags.Public | BindingFlags.Instance)); + foreach (var field in fields) + { + var value = field.GetValue(obj); + dictionary[field.Name] = ConvertValue(value, depth - 1); + } + + return dictionary; + } + + private static object ConvertValue(object value, int depth) + { + if (value == null) return null; + + if (value is IEnumerable enumerable && !(value is string)) + { + var list = new List(); + foreach (var item in enumerable) + { + list.Add(ConvertValue(item, depth - 1)); + } + return list; + } + + if (value.GetType().IsClass && !(value is string)) + { + return ToDictionaryRecursive(value, depth - 1); + } + + return value; + } +} diff --git a/src/CloudGaming/Console/CloudGaming.Test/Program.cs b/src/CloudGaming/Console/CloudGaming.Test/Program.cs new file mode 100644 index 0000000..1b850f9 --- /dev/null +++ b/src/CloudGaming/Console/CloudGaming.Test/Program.cs @@ -0,0 +1,24 @@ +// See https://aka.ms/new-console-template for more information +using CloudGaming.DtoModel; +using CloudGaming.Test; + +using Newtonsoft.Json; + +using System.Reflection; + +Console.WriteLine("Hello, World!"); +AppConfigDto appConfigDto = new AppConfigDto() +{ + //AppConfigExtend = new AppConfigExtend() + //{ + // TestImage = 1 + //}, + //CheckingGames = new List() { "iu","cg111"}, + //IsChecking = true, + //HighDelay = true, + //OpenImage = 1, + //MyProperty = "test" +}; +var dic = appConfigDto.ToDictionary(15); +Console.WriteLine(JsonConvert.SerializeObject(dic)); +Console.ReadKey(); diff --git a/src/CloudGaming/Model/CloudGaming.DtoModel/AppConfigDto.cs b/src/CloudGaming/Model/CloudGaming.DtoModel/AppConfigDto.cs index 02d3dab..451ffff 100644 --- a/src/CloudGaming/Model/CloudGaming.DtoModel/AppConfigDto.cs +++ b/src/CloudGaming/Model/CloudGaming.DtoModel/AppConfigDto.cs @@ -18,36 +18,20 @@ public class AppConfigDto /// public bool IsChecking { get; set; } - /// - /// 版本审核中可玩游戏(在谷歌包的审核模式下可以玩的游戏列表) - /// - public List CheckingGames = new List(); + /// /// 是否开启实名认证 /// public bool IsAuthRealName { get; set; } - /// - /// 是否是高延迟地区 - /// - public bool HighDelay { get; set; } - - /// - /// 开屏图 - /// - [Images] - public int OpenImage { get; set; } + ///// + ///// 开屏图 + ///// + //[Images] + //public int OpenImage { get; set; } + - public AppConfigExtend AppConfigExtend { get; set; } } -public class AppConfigExtend -{ - /// - /// 开屏图 - /// - [Images] - public int TestImage { get; set; } -} diff --git a/src/CloudGaming/Utile/HuanMeng.DotNetCore/Utility/ObjectExtensions.cs b/src/CloudGaming/Utile/HuanMeng.DotNetCore/Utility/ObjectExtensions.cs new file mode 100644 index 0000000..f15f5bf --- /dev/null +++ b/src/CloudGaming/Utile/HuanMeng.DotNetCore/Utility/ObjectExtensions.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Concurrent; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using HuanMeng.DotNetCore.AttributeExtend; + +namespace HuanMeng.DotNetCore.Utility; + +public static class ObjectExtensions +{ + /// + /// 缓存属性信息以提高反射访问的性能,使用 ConcurrentDictionary 确保线程安全 + /// + private static readonly ConcurrentDictionary PropertyCache = new(); + /// + /// 缓存字段信息以提高反射访问的性能,使用 ConcurrentDictionary 确保线程安全 + /// + private static readonly ConcurrentDictionary FieldCache = new(); + + /// + /// 将对象转换为 Dictionary 类型。 + /// + /// 要转换的对象。 + /// 最大递归深度,以控制嵌套对象的转换层数。 + /// 包含对象属性和值的字典。 + public static Dictionary ToDictionary(this object obj, int maxDepth = 3) + { + return ToDictionaryRecursive(obj, maxDepth); + } + + /// + /// 递归地将对象转换为 Dictionary。 + /// + /// 要转换的对象。 + /// 当前递归深度。 + /// 包含对象属性和值的字典。 + private static Dictionary ToDictionaryRecursive(object obj, int depth) + { + // 检查对象是否为 null 或递归深度是否小于 0,若是则返回 null + if (obj == null || depth < 0) + return null; + + var dictionary = new Dictionary(); + var type = obj.GetType(); + + // 获取对象的属性信息,若类型已缓存则直接使用缓存中的信息 + var properties = PropertyCache.GetOrAdd(type, t => t.GetProperties(BindingFlags.Public | BindingFlags.Instance)); + foreach (var property in properties) + { + var value = property.GetValue(obj); + var imagesAttribute = property.GetCustomAttribute(); + if (imagesAttribute != null) + { + string keyName = property.Name; + if (!string.IsNullOrEmpty(imagesAttribute.FieldName)) + { + keyName = imagesAttribute.FieldName; + } + dictionary[keyName] = $"[Images]{value.ToString()}"; + continue; + } + // 获取属性值并递归转换 + + dictionary[property.Name] = ConvertValue(value, depth - 1); + } + + // 获取对象的字段信息,若类型已缓存则直接使用缓存中的信息 + //var fields = FieldCache.GetOrAdd(type, t => t.GetFields(BindingFlags.Public | BindingFlags.Instance)); + //foreach (var field in fields) + //{ + // //var imagesAttribute = field.GetCustomAttribute(); + // //if (imagesAttribute != null) + // //{ + // // Console.WriteLine($"带有 [Images] 特性的成员:{field.Name}"); + // // Console.WriteLine($"FieldName 属性值:{imagesAttribute?.FieldName}"); + // //} + // // 获取字段值并递归转换 + // var value = field.GetValue(obj); + // dictionary[field.Name] = ConvertValue(value, depth - 1); + //} + + return dictionary; + } + + /// + /// 将属性或字段值转换为适当的类型。 + /// + /// 要转换的值。 + /// 当前递归深度。 + /// 转换后的值,可能是基本类型、字典或列表。 + private static object ConvertValue(object value, int depth) + { + if (value == null) return null; + + // 检查是否为集合类型(非字符串),如果是则递归转换集合中的每个元素 + if (value is IEnumerable enumerable && !(value is string)) + { + var list = new List(); + foreach (var item in enumerable) + { + list.Add(ConvertValue(item, depth - 1)); + } + return list; + } + + // 如果是类且非字符串,则递归转换为字典类型 + if (value.GetType().IsClass && !(value is string)) + { + return ToDictionaryRecursive(value, depth - 1); + } + + // 对于基本类型或字符串,直接返回值 + return value; + } +} \ No newline at end of file