多语言v1
This commit is contained in:
parent
8caaffdb11
commit
afae8967ee
116
src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppLanguage.cs
Normal file
116
src/CloudGaming/Code/CloudGaming.Code/AppExtend/AppLanguage.cs
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudGaming.Code.AppExtend;
|
||||
/// <summary>
|
||||
/// app多语言
|
||||
/// </summary>
|
||||
public static class AppLanguage
|
||||
{
|
||||
/// <summary>
|
||||
/// 多语言管理
|
||||
/// </summary>
|
||||
public static ConcurrentDictionary<string, ConcurrentDictionary<string, ConcurrentDictionary<string, ConcurrentDictionary<string, string>>>> AppConfigLanguages { get; set; } = new ConcurrentDictionary<string, ConcurrentDictionary<string, ConcurrentDictionary<string, ConcurrentDictionary<string, string>>>>();
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前项目的多语言配置
|
||||
/// </summary>
|
||||
/// <param name="appConfig"></param>
|
||||
/// <returns></returns>
|
||||
public static ConcurrentDictionary<string, ConcurrentDictionary<string, ConcurrentDictionary<string, string>>> GetAppConfigLanguage(this AppConfig appConfig)
|
||||
{
|
||||
if (!AppConfigLanguages.TryGetValue(appConfig.Identifier, out var language))
|
||||
{
|
||||
language = new ConcurrentDictionary<string, ConcurrentDictionary<string, ConcurrentDictionary<string, string>>>();
|
||||
AppConfigLanguages.TryAdd(appConfig.Identifier, language);
|
||||
}
|
||||
return language;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前接口的多语言配置
|
||||
/// </summary>
|
||||
/// <param name="appConfig"></param>
|
||||
/// <param name="language">api地址</param>
|
||||
/// <returns></returns>
|
||||
public static ConcurrentDictionary<string, ConcurrentDictionary<string, string>> GetAppLanguage(this AppConfig appConfig, string language)
|
||||
{
|
||||
var dic = GetAppConfigLanguage(appConfig);
|
||||
|
||||
if (!dic.TryGetValue(language, out var languageDic))
|
||||
{
|
||||
languageDic = new ConcurrentDictionary<string, ConcurrentDictionary<string, string>>();
|
||||
dic.TryAdd(language, languageDic);
|
||||
}
|
||||
|
||||
return languageDic;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前接口的多语言配置
|
||||
/// </summary>
|
||||
/// <param name="appConfig"></param>
|
||||
/// <param name="language">api地址</param>
|
||||
/// <returns></returns>
|
||||
public static ConcurrentDictionary<string, string> GetAppApiLanguage(this AppConfig appConfig, string language, string api)
|
||||
{
|
||||
var dic = GetAppLanguage(appConfig, language);
|
||||
|
||||
if (!dic.TryGetValue(api, out var languageDic))
|
||||
{
|
||||
languageDic = new ConcurrentDictionary<string, string>();
|
||||
dic.TryAdd(api, languageDic);
|
||||
}
|
||||
|
||||
return languageDic;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载多语言配置
|
||||
/// </summary>
|
||||
/// <param name="appConfig"></param>
|
||||
/// <param name="json"></param>
|
||||
public static void InitAppLanguage(this AppConfig appConfig, string _language, string json)
|
||||
{
|
||||
if (AppConfigLanguages == null)
|
||||
{
|
||||
AppConfigLanguages = new ConcurrentDictionary<string, ConcurrentDictionary<string, ConcurrentDictionary<string, ConcurrentDictionary<string, string>>>>();
|
||||
}
|
||||
//获取当前项目的多语言配置
|
||||
var appLanguage = AppConfigLanguages.GetOrAdd(appConfig.Identifier, (t) => new ConcurrentDictionary<string, ConcurrentDictionary<string, ConcurrentDictionary<string, string>>>());
|
||||
//初始化json数据
|
||||
var cacheLanguage = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, string>>>(json);
|
||||
//重新定义当前项目的多语言
|
||||
var innerDict = new ConcurrentDictionary<string, ConcurrentDictionary<string, string>>();
|
||||
foreach (var item in cacheLanguage)
|
||||
{
|
||||
|
||||
var t = new ConcurrentDictionary<string, string>(item.Value);
|
||||
innerDict.TryAdd(item.Key, t);
|
||||
}
|
||||
appLanguage.AddOrUpdate(_language, (t) => innerDict, (t, o) => innerDict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存多语言配置
|
||||
/// </summary>
|
||||
/// <param name="appConfig"></param>
|
||||
/// <returns></returns>
|
||||
public static string LanguageToJson(AppConfig appConfig)
|
||||
{
|
||||
var settings = new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver()
|
||||
};
|
||||
var appLanguage = GetAppConfigLanguage(appConfig);
|
||||
var json = JsonConvert.SerializeObject(appLanguage, settings);
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
|
@ -28,6 +28,9 @@ public class AppService(IServiceProvider scopeFactory) : IHostedService
|
|||
CloudGamingBase cloudGamingBase = new CloudGamingBase(scopedProvider);
|
||||
//加载图片缓存
|
||||
cloudGamingBase.Cache.AppImageCache.ReloadData();
|
||||
//cloudGamingBase.RedisCache.StringGet("language");
|
||||
//appConfig.InitAppLanguage();
|
||||
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,15 +88,22 @@ public class CustomResultFilter : IResultFilter
|
|||
}
|
||||
}
|
||||
}
|
||||
var dic = value.ToDictionaryOrList(apiPrefix, it => cloudGamingBase.Cache.AppImageCache[it]);
|
||||
var language = _appConfig.GetAppLanguage(apiPrefix);
|
||||
var dic = value.ToDictionaryOrList(false, apiPrefix, it => cloudGamingBase.Cache.AppImageCache[it], (value, prefix, isArray) =>
|
||||
{
|
||||
if (value.ContainsChineseOptimized())
|
||||
{
|
||||
//中文
|
||||
var v = language.GetOrAdd(value, value);
|
||||
if (!string.IsNullOrEmpty(v))
|
||||
{
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
});
|
||||
objectResult.Value = dic;
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// //value = objectResult.Value;
|
||||
//}
|
||||
|
||||
|
||||
sw.Stop();
|
||||
context.HttpContext.Response.Headers.TryAdd("X-Request-Duration-Filter", sw.Elapsed.TotalMilliseconds.ToString());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,15 +44,15 @@ public static class ObjectExtensions
|
|||
/// <param name="obj">要转换的对象。</param>
|
||||
/// <param name="prefix">属性路径的可选前缀。</param>
|
||||
/// <returns>对象的字典或列表表示形式。</returns>
|
||||
public static object ToDictionaryOrList(this object obj, string prefix = "", Func<int, string>? imageFunc = null)
|
||||
public static object ToDictionaryOrList(this object obj, bool isEnumerable, string prefix = "", Func<int, string>? imageFunc = null, Func<string, string, bool, string>? languageFunc = null)
|
||||
{
|
||||
if (obj == null) return null;
|
||||
|
||||
return obj switch
|
||||
{
|
||||
_ when IsPrimitiveType(obj) => obj,
|
||||
IEnumerable enumerable => TransformCollection(enumerable, prefix, imageFunc),
|
||||
_ => TransformObject(obj, prefix, imageFunc)
|
||||
IEnumerable enumerable => TransformCollection(enumerable, prefix, imageFunc, languageFunc),
|
||||
_ => TransformObject(obj, isEnumerable, prefix, imageFunc, languageFunc)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -62,13 +62,13 @@ public static class ObjectExtensions
|
|||
/// <param name="enumerable">要转换的集合。</param>
|
||||
/// <param name="prefix">集合中每个属性路径的前缀。</param>
|
||||
/// <returns>转换后的项列表。</returns>
|
||||
private static List<object> TransformCollection(IEnumerable enumerable, string prefix = "", Func<int, string>? imageFunc = null)
|
||||
private static List<object> TransformCollection(IEnumerable enumerable, string prefix = "", Func<int, string>? imageFunc = null, Func<string, string, bool, string>? languageFunc = null)
|
||||
{
|
||||
var list = new List<object>(enumerable is ICollection collection ? collection.Count : 10);
|
||||
int index = 0;
|
||||
foreach (var item in enumerable)
|
||||
{
|
||||
list.Add(ToDictionaryOrList(item, $"{prefix}.[{index}]", imageFunc)); // 为集合中每个项添加路径
|
||||
list.Add(ToDictionaryOrList(item, true, $"{prefix}.[{index}]", imageFunc, languageFunc)); // 为集合中每个项添加路径
|
||||
index++;
|
||||
}
|
||||
return list;
|
||||
|
|
@ -80,7 +80,7 @@ public static class ObjectExtensions
|
|||
/// <param name="obj">要转换的对象。</param>
|
||||
/// <param name="prefix">每个属性路径的前缀。</param>
|
||||
/// <returns>包含属性名和属性值的字典。</returns>
|
||||
private static Dictionary<string, object> TransformObject(object obj, string prefix = "", Func<int, string>? imageFunc = null)
|
||||
private static Dictionary<string, object> TransformObject(object obj, bool isEnumerable, string prefix = "", Func<int, string>? imageFunc = null, Func<string, string, bool, string>? languageFunc = null)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
|
|
@ -100,8 +100,16 @@ public static class ObjectExtensions
|
|||
// 如果属性是字符串,在其值前添加 "test"
|
||||
if (propertyValue is string stringValue)
|
||||
{
|
||||
if (stringValue == null)
|
||||
{
|
||||
keyValuePairs[accessor.PropertyName] = "";
|
||||
continue;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(stringValue) && languageFunc != null)
|
||||
{
|
||||
stringValue = languageFunc?.Invoke(stringValue, propertyPath, false) ?? "";
|
||||
}
|
||||
keyValuePairs[accessor.PropertyName] = stringValue;
|
||||
//Console.WriteLine(propertyPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +117,7 @@ public static class ObjectExtensions
|
|||
// 否则,如果是集合类型,则递归转换
|
||||
keyValuePairs[accessor.PropertyName] = accessor.HasImagesAttribute
|
||||
? imageFunc?.Invoke((int)propertyValue) ?? ""
|
||||
: ToDictionaryOrList(propertyValue, propertyPath, imageFunc); // IsCollectionType(propertyValue) ?: propertyValue;
|
||||
: ToDictionaryOrList(propertyValue, isEnumerable, propertyPath, imageFunc, languageFunc); // IsCollectionType(propertyValue) ?: propertyValue;
|
||||
}
|
||||
|
||||
return keyValuePairs;
|
||||
|
|
|
|||
|
|
@ -1,585 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using HuanMeng.DotNetCore.AttributeExtend;
|
||||
using System.Linq.Expressions;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
|
||||
namespace HuanMeng.DotNetCore.Utility;
|
||||
|
||||
|
||||
[Obsolete]
|
||||
public static class ObjectExtensions11
|
||||
{
|
||||
/// <summary>
|
||||
/// 缓存属性信息以提高反射访问的性能,使用 ConcurrentDictionary 确保线程安全
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<Type, PropertyInfo[]> PropertyCache = new();
|
||||
|
||||
/// <summary>
|
||||
/// 判断对象是否为基础类型。
|
||||
/// </summary>
|
||||
public static bool IsPrimitiveType(object obj) =>
|
||||
obj is not null && (obj.GetType().IsPrimitive || obj is string or ValueType);
|
||||
|
||||
/// <summary>
|
||||
/// 判断对象是否为集合类型(排除字符串)。
|
||||
/// </summary>
|
||||
public static bool IsCollectionType(object obj) => obj is IEnumerable && obj is not string;
|
||||
|
||||
/// <summary>
|
||||
/// 判断对象是否为复杂类型。
|
||||
/// </summary>
|
||||
public static bool IsComplexType(object obj) =>
|
||||
obj is not null && !IsPrimitiveType(obj) && !IsCollectionType(obj);
|
||||
|
||||
/// <summary>
|
||||
/// 转换对象为字典或列表
|
||||
/// </summary>
|
||||
public static object ToDictionaryOrList(object obj)
|
||||
{
|
||||
if (obj == null) return null;
|
||||
|
||||
return obj switch
|
||||
{
|
||||
// 基础类型
|
||||
_ when IsPrimitiveType(obj) => obj,
|
||||
// 集合类型
|
||||
IEnumerable enumerable => TransformCollection(enumerable),
|
||||
// 复杂类型
|
||||
_ => TransformObject(obj)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换集合为列表
|
||||
/// </summary>
|
||||
private static List<object> TransformCollection(IEnumerable enumerable)
|
||||
{
|
||||
var list = new List<object>();
|
||||
foreach (var item in enumerable)
|
||||
{
|
||||
list.Add(item.ToDictionaryOrList());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换对象为字典
|
||||
/// </summary>
|
||||
private static Dictionary<string, object> TransformObject(object obj)
|
||||
{
|
||||
var type = obj.GetType();
|
||||
var properties = PropertyCache.GetOrAdd(type, t => t.GetProperties(BindingFlags.Public | BindingFlags.Instance));
|
||||
var keyValuePairs = new Dictionary<string, object>();
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
var propertyValue = property.GetValue(obj);
|
||||
keyValuePairs[property.Name] = IsCollectionType(propertyValue)
|
||||
? propertyValue.ToDictionaryOrList()
|
||||
: propertyValue;
|
||||
}
|
||||
|
||||
return keyValuePairs;
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public static class ObjectExtensions1
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Type, PropertyInfo[]> PropertyCache = new();
|
||||
private static readonly ConcurrentDictionary<PropertyInfo, bool> HasImagesAttributeCache = new();
|
||||
|
||||
public static bool IsPrimitiveType(object obj) =>
|
||||
obj is not null && (obj.GetType().IsPrimitive || obj is string or ValueType);
|
||||
|
||||
public static bool IsCollectionType(object obj) => obj is IEnumerable && obj is not string;
|
||||
|
||||
public static bool IsComplexType(object obj) =>
|
||||
obj is not null && !IsPrimitiveType(obj) && !IsCollectionType(obj);
|
||||
|
||||
public static object ToDictionaryOrList(object obj)
|
||||
{
|
||||
if (obj == null) return null;
|
||||
|
||||
return obj switch
|
||||
{
|
||||
_ when IsPrimitiveType(obj) => obj,
|
||||
IEnumerable enumerable => TransformCollection(enumerable),
|
||||
_ => TransformObject(obj)
|
||||
};
|
||||
}
|
||||
|
||||
private static List<object> TransformCollection(IEnumerable enumerable)
|
||||
{
|
||||
var list = new List<object>(enumerable is ICollection collection ? collection.Count : 10);
|
||||
foreach (var item in enumerable)
|
||||
{
|
||||
list.Add(ToDictionaryOrList(item));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static Dictionary<string, object> TransformObject(object obj)
|
||||
{
|
||||
var type = obj.GetType();
|
||||
var properties = PropertyCache.GetOrAdd(type, t => t.GetProperties(BindingFlags.Public | BindingFlags.Instance));
|
||||
var keyValuePairs = new Dictionary<string, object>(properties.Length);
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
// 预先缓存 ImagesAttribute 判断结果
|
||||
if (!HasImagesAttributeCache.TryGetValue(property, out bool hasImagesAttribute))
|
||||
{
|
||||
hasImagesAttribute = property.GetCustomAttribute<ImagesAttribute>() != null;
|
||||
HasImagesAttributeCache.TryAdd(property, hasImagesAttribute);
|
||||
}
|
||||
var propertyValue = property.GetValue(obj);
|
||||
if (hasImagesAttribute)
|
||||
{
|
||||
keyValuePairs[property.Name] = $"image{propertyValue}";
|
||||
continue;
|
||||
}
|
||||
|
||||
keyValuePairs[property.Name] = IsCollectionType(propertyValue)
|
||||
? ToDictionaryOrList(propertyValue)
|
||||
: propertyValue;
|
||||
if (propertyValue is IEnumerable imagesEnumerable)
|
||||
{
|
||||
keyValuePairs[property.Name] = TransformCollection(imagesEnumerable);
|
||||
}
|
||||
}
|
||||
|
||||
return keyValuePairs;
|
||||
}
|
||||
}
|
||||
[Obsolete]
|
||||
public static class ObjectExtensions3
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Type, PropertyAccessor[]> PropertyAccessorsCache = new();
|
||||
private static readonly ConcurrentDictionary<PropertyInfo, bool> HasImagesAttributeCache = new();
|
||||
public static bool IsPrimitiveType(object obj) =>
|
||||
obj is not null && (obj.GetType().IsPrimitive || obj is string or ValueType);
|
||||
|
||||
public static bool IsCollectionType(object obj) => obj is IEnumerable && obj is not string;
|
||||
|
||||
public static object ToDictionaryOrList(object obj)
|
||||
{
|
||||
if (obj == null) return null;
|
||||
|
||||
return obj switch
|
||||
{
|
||||
_ when IsPrimitiveType(obj) => obj,
|
||||
IEnumerable enumerable => TransformCollection(enumerable),
|
||||
_ => TransformObject(obj)
|
||||
};
|
||||
}
|
||||
|
||||
private static List<object> TransformCollection(IEnumerable enumerable)
|
||||
{
|
||||
var list = new List<object>();
|
||||
foreach (var item in enumerable)
|
||||
{
|
||||
list.Add(ToDictionaryOrList(item));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static Dictionary<string, object> TransformObject(object obj)
|
||||
{
|
||||
var type = obj.GetType();
|
||||
var accessors = PropertyAccessorsCache.GetOrAdd(type, CreatePropertyAccessors);
|
||||
var keyValuePairs = new Dictionary<string, object>(accessors.Length);
|
||||
|
||||
foreach (var accessor in accessors)
|
||||
{
|
||||
var propertyValue = accessor.Getter(obj);
|
||||
keyValuePairs[accessor.Name] = IsCollectionType(propertyValue)
|
||||
? ToDictionaryOrList(propertyValue)
|
||||
: propertyValue;
|
||||
}
|
||||
|
||||
return keyValuePairs;
|
||||
}
|
||||
|
||||
private static PropertyAccessor[] CreatePropertyAccessors(Type type)
|
||||
{
|
||||
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
var accessors = new PropertyAccessor[properties.Length];
|
||||
|
||||
for (int i = 0; i < properties.Length; i++)
|
||||
{
|
||||
var property = properties[i];
|
||||
//var x = property.GetCustomAttribute<ImagesAttribute>() != null;
|
||||
|
||||
var getter = CreateGetter(property);
|
||||
accessors[i] = new PropertyAccessor(property.Name, getter);
|
||||
}
|
||||
|
||||
return accessors;
|
||||
}
|
||||
|
||||
private static Func<object, object> CreateGetter(PropertyInfo property)
|
||||
{
|
||||
var parameter = Expression.Parameter(typeof(object), "instance");
|
||||
var castInstance = Expression.Convert(parameter, property.DeclaringType);
|
||||
var propertyAccess = Expression.Property(castInstance, property);
|
||||
var castResult = Expression.Convert(propertyAccess, typeof(object));
|
||||
var lambda = Expression.Lambda<Func<object, object>>(castResult, parameter);
|
||||
return lambda.Compile();
|
||||
}
|
||||
|
||||
private record PropertyAccessor(string Name, Func<object, object> Getter);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public static class ObjectExtensions5
|
||||
{
|
||||
// 用于缓存每个类型的属性访问器数组,以减少重复的反射操作
|
||||
private static readonly ConcurrentDictionary<Type, PropertyAccessor[]> PropertyCache = new();
|
||||
|
||||
// 判断对象是否为原始类型、字符串或值类型
|
||||
public static bool IsPrimitiveType(object obj) =>
|
||||
obj is not null && (obj.GetType().IsPrimitive || obj is string or ValueType);
|
||||
|
||||
// 判断对象是否为集合类型(非字符串的 IEnumerable)
|
||||
public static bool IsCollectionType(object obj) => obj is IEnumerable && obj is not string;
|
||||
|
||||
/// <summary>
|
||||
/// 将对象转换为字典或列表结构
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static object ToDictionaryOrList(object obj)
|
||||
{
|
||||
if (obj == null) return null;
|
||||
|
||||
// 根据对象类型执行相应的转换操作
|
||||
return obj switch
|
||||
{
|
||||
_ when IsPrimitiveType(obj) => obj, // 原始类型直接返回
|
||||
IEnumerable enumerable => TransformCollection(enumerable), // 集合类型转换为列表
|
||||
_ => TransformObject(obj) // 复杂类型转换为字典
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换集合类型,将每个元素递归转换为字典或列表
|
||||
/// </summary>
|
||||
/// <param name="enumerable"></param>
|
||||
/// <returns></returns>
|
||||
private static List<object> TransformCollection(IEnumerable enumerable)
|
||||
{
|
||||
var list = new List<object>(enumerable is ICollection collection ? collection.Count : 10);
|
||||
foreach (var item in enumerable)
|
||||
{
|
||||
list.Add(ToDictionaryOrList(item));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
// 转换复杂类型为字典结构,键为属性名,值为属性值
|
||||
private static Dictionary<string, object> TransformObject(object obj)
|
||||
{
|
||||
var type = obj.GetType();
|
||||
|
||||
// 从缓存中获取或创建该类型的属性访问器数组
|
||||
var accessors = PropertyCache.GetOrAdd(type, t => CreatePropertyAccessors(t));
|
||||
var keyValuePairs = new Dictionary<string, object>(accessors.Length);
|
||||
|
||||
// 遍历每个属性访问器
|
||||
foreach (var accessor in accessors)
|
||||
{
|
||||
// 使用表达式树生成的委托获取属性值
|
||||
var propertyValue = accessor.Getter(obj);
|
||||
|
||||
// 如果属性具有 ImagesAttribute 特性,将其值转换为 "image{propertyValue}" 格式
|
||||
if (accessor.HasImagesAttribute)
|
||||
{
|
||||
keyValuePairs[accessor.PropertyName] = $"image{propertyValue}";
|
||||
}
|
||||
else
|
||||
{
|
||||
// 根据属性值的类型决定是否递归转换
|
||||
keyValuePairs[accessor.PropertyName] = IsCollectionType(propertyValue)
|
||||
? ToDictionaryOrList(propertyValue)
|
||||
: propertyValue;
|
||||
}
|
||||
}
|
||||
|
||||
return keyValuePairs;
|
||||
}
|
||||
|
||||
// 创建指定类型的属性访问器数组
|
||||
private static PropertyAccessor[] CreatePropertyAccessors(Type type)
|
||||
{
|
||||
// 获取类型的公共实例属性
|
||||
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
var accessors = new List<PropertyAccessor>(properties.Length);
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
// 使用表达式树生成委托来获取属性值,避免使用反射
|
||||
var parameter = Expression.Parameter(typeof(object), "obj"); // 输入参数 obj
|
||||
var castParameter = Expression.Convert(parameter, type); // 将参数转换为目标类型
|
||||
var propertyAccess = Expression.Property(castParameter, property); // 获取属性值
|
||||
var convertPropertyAccess = Expression.Convert(propertyAccess, typeof(object)); // 转换为 object 类型
|
||||
var getter = Expression.Lambda<Func<object, object>>(convertPropertyAccess, parameter).Compile();
|
||||
|
||||
// 检查属性是否具有 ImagesAttribute 特性
|
||||
bool hasImagesAttribute = property.GetCustomAttribute<ImagesAttribute>() != null;
|
||||
|
||||
// 将属性名、Getter 委托和特性标识添加到 PropertyAccessor 对象中
|
||||
accessors.Add(new PropertyAccessor(property.Name, getter, hasImagesAttribute));
|
||||
}
|
||||
|
||||
return accessors.ToArray();
|
||||
}
|
||||
|
||||
// 表示属性访问器的类,包含属性名称、Getter 委托和特性标识
|
||||
private class PropertyAccessor
|
||||
{
|
||||
public string PropertyName { get; } // 属性名称
|
||||
public Func<object, object> Getter { get; } // 委托,用于获取属性值
|
||||
public bool HasImagesAttribute { get; } // 是否包含 ImagesAttribute 特性
|
||||
|
||||
public PropertyAccessor(string propertyName, Func<object, object> getter, bool hasImagesAttribute)
|
||||
{
|
||||
PropertyName = propertyName;
|
||||
Getter = getter;
|
||||
HasImagesAttribute = hasImagesAttribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public static class ObjectExtensions6
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用线程安全的字典缓存每个类型的属性访问器
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<Type, PropertyAccessor[]> PropertyCache = new();
|
||||
/// <summary>
|
||||
/// 缓存每个属性是否具有 ImagesAttribute 特性
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<PropertyInfo, bool> _PropertyCache = new ConcurrentDictionary<PropertyInfo, bool>();
|
||||
|
||||
/// <summary>
|
||||
/// 判断对象是否为原始类型或字符串
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsPrimitiveType(object obj) =>
|
||||
obj is not null && (obj.GetType().IsPrimitive || obj is string or ValueType);
|
||||
|
||||
/// <summary>
|
||||
/// 判断对象是否为集合类型(但不是字符串)
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsCollectionType(object obj) => obj is IEnumerable && obj is not string;
|
||||
|
||||
/// <summary>
|
||||
/// 将对象转换为字典或列表
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static object ToDictionaryOrList(object obj)
|
||||
{
|
||||
if (obj == null) return null;
|
||||
|
||||
return obj switch
|
||||
{
|
||||
_ when IsPrimitiveType(obj) => obj,
|
||||
IEnumerable enumerable => TransformCollection(enumerable),
|
||||
_ => TransformObject(obj)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将集合转换为列表
|
||||
/// </summary>
|
||||
/// <param name="enumerable"></param>
|
||||
/// <returns></returns>
|
||||
private static List<object> TransformCollection(IEnumerable enumerable)
|
||||
{
|
||||
// 如果集合实现了 ICollection 接口,则使用其 Count 属性初始化列表容量
|
||||
var list = new List<object>(enumerable is ICollection collection ? collection.Count : 10);
|
||||
foreach (var item in enumerable)
|
||||
{
|
||||
list.Add(ToDictionaryOrList(item));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
// 将对象转换为字典
|
||||
private static Dictionary<string, object> TransformObject(object obj)
|
||||
{
|
||||
var type = obj.GetType();
|
||||
// 获取或创建该类型的属性访问器
|
||||
var accessors = PropertyCache.GetOrAdd(type, t => CreatePropertyAccessors(t));
|
||||
var keyValuePairs = new Dictionary<string, object>(accessors.Length);
|
||||
|
||||
foreach (var accessor in accessors)
|
||||
{
|
||||
var propertyValue = accessor.Getter(obj);
|
||||
|
||||
if (accessor.HasImagesAttribute)
|
||||
{
|
||||
// 如果属性具有 ImagesAttribute 特性,处理方式不同
|
||||
keyValuePairs[accessor.PropertyName] = $"image{propertyValue}";
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果属性是集合类型,递归转换
|
||||
keyValuePairs[accessor.PropertyName] = IsCollectionType(propertyValue)
|
||||
? ToDictionaryOrList(propertyValue)
|
||||
: propertyValue;
|
||||
}
|
||||
}
|
||||
|
||||
return keyValuePairs;
|
||||
}
|
||||
|
||||
// 创建属性访问器数组
|
||||
private static PropertyAccessor[] CreatePropertyAccessors(Type type)
|
||||
{
|
||||
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
var accessors = new List<PropertyAccessor>(properties.Length);
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
var parameter = Expression.Parameter(typeof(object), "obj");
|
||||
var castParameter = Expression.Convert(parameter, type);
|
||||
var propertyAccess = Expression.Property(castParameter, property);
|
||||
var convertPropertyAccess = Expression.Convert(propertyAccess, typeof(object));
|
||||
var getter = Expression.Lambda<Func<object, object>>(convertPropertyAccess, parameter).Compile();
|
||||
|
||||
// 使用缓存检查属性是否具有 ImagesAttribute 特性
|
||||
bool hasImagesAttribute = GetHasImagesAttribute(property, _PropertyCache);
|
||||
|
||||
accessors.Add(new PropertyAccessor(property.Name, getter, hasImagesAttribute));
|
||||
}
|
||||
|
||||
return accessors.ToArray();
|
||||
}
|
||||
|
||||
// 检查属性是否具有 ImagesAttribute 特性,并缓存结果
|
||||
private static bool GetHasImagesAttribute(PropertyInfo property, ConcurrentDictionary<PropertyInfo, bool> propertyCache)
|
||||
{
|
||||
if (propertyCache.TryGetValue(property, out bool hasImagesAttribute))
|
||||
{
|
||||
return hasImagesAttribute;
|
||||
}
|
||||
|
||||
hasImagesAttribute = property.GetCustomAttribute<ImagesAttribute>() != null;
|
||||
propertyCache[property] = hasImagesAttribute;
|
||||
|
||||
return hasImagesAttribute;
|
||||
}
|
||||
|
||||
// 属性访问器类,包含属性名、获取器和特性标志
|
||||
private class PropertyAccessor
|
||||
{
|
||||
public string PropertyName { get; }
|
||||
public Func<object, object> Getter { get; }
|
||||
public bool HasImagesAttribute { get; }
|
||||
|
||||
public PropertyAccessor(string propertyName, Func<object, object> getter, bool hasImagesAttribute)
|
||||
{
|
||||
PropertyName = propertyName;
|
||||
Getter = getter;
|
||||
HasImagesAttribute = hasImagesAttribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public static class ObjectExtensions7
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Type, PropertyAccessor[]> PropertyCache = new();
|
||||
private static readonly ConcurrentDictionary<PropertyInfo, bool> _PropertyCache = new();
|
||||
|
||||
public static bool IsPrimitiveType(object obj) =>
|
||||
obj is not null && (obj.GetType().IsPrimitive || obj is string or ValueType);
|
||||
|
||||
public static bool IsCollectionType(object obj) => obj is IEnumerable && obj is not string;
|
||||
|
||||
public static object ToDictionaryOrList(object obj)
|
||||
{
|
||||
if (obj == null) return null;
|
||||
|
||||
return obj switch
|
||||
{
|
||||
_ when IsPrimitiveType(obj) => obj,
|
||||
IEnumerable enumerable => TransformCollection(enumerable),
|
||||
_ => TransformObject(obj)
|
||||
};
|
||||
}
|
||||
|
||||
private static List<object> TransformCollection(IEnumerable enumerable)
|
||||
{
|
||||
var list = new List<object>(enumerable is ICollection collection ? collection.Count : 10);
|
||||
foreach (var item in enumerable)
|
||||
{
|
||||
list.Add(ToDictionaryOrList(item));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static Dictionary<string, object> TransformObject(object obj)
|
||||
{
|
||||
var type = obj.GetType();
|
||||
var accessors = PropertyCache.GetOrAdd(type, CreatePropertyAccessors);
|
||||
var keyValuePairs = new Dictionary<string, object>(accessors.Length);
|
||||
|
||||
foreach (var accessor in accessors)
|
||||
{
|
||||
var propertyValue = accessor.Getter(obj);
|
||||
keyValuePairs[accessor.PropertyName] = accessor.HasImagesAttribute
|
||||
? $"image{propertyValue}"
|
||||
: IsCollectionType(propertyValue) ? ToDictionaryOrList(propertyValue) : propertyValue;
|
||||
}
|
||||
|
||||
return keyValuePairs;
|
||||
}
|
||||
|
||||
private static PropertyAccessor[] CreatePropertyAccessors(Type type)
|
||||
{
|
||||
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
return properties.Select(property =>
|
||||
{
|
||||
var getter = CreatePropertyGetter(type, property);
|
||||
bool hasImagesAttribute = _PropertyCache.GetOrAdd(property, p => p.GetCustomAttribute<ImagesAttribute>() != null);
|
||||
return new PropertyAccessor(property.Name, getter, hasImagesAttribute);
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
private static Func<object, object> CreatePropertyGetter(Type type, PropertyInfo property)
|
||||
{
|
||||
var parameter = Expression.Parameter(typeof(object), "obj");
|
||||
var castParameter = Expression.Convert(parameter, type);
|
||||
var propertyAccess = Expression.Property(castParameter, property);
|
||||
var convertPropertyAccess = Expression.Convert(propertyAccess, typeof(object));
|
||||
return Expression.Lambda<Func<object, object>>(convertPropertyAccess, parameter).Compile();
|
||||
}
|
||||
|
||||
private class PropertyAccessor
|
||||
{
|
||||
public string PropertyName { get; }
|
||||
public Func<object, object> Getter { get; }
|
||||
public bool HasImagesAttribute { get; }
|
||||
|
||||
public PropertyAccessor(string propertyName, Func<object, object> getter, bool hasImagesAttribute)
|
||||
{
|
||||
PropertyName = propertyName;
|
||||
Getter = getter;
|
||||
HasImagesAttribute = hasImagesAttribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace HuanMeng.DotNetCore.Utility;
|
||||
|
||||
/// <summary>
|
||||
/// 字符串扩展
|
||||
/// </summary>
|
||||
public static class StringExtend
|
||||
{
|
||||
/// <summary>
|
||||
/// 判断字符串是否包含中文字符(使用字符遍历)
|
||||
/// </summary>
|
||||
/// <param name="input">需要检查的字符串</param>
|
||||
/// <returns>如果包含中文字符,则返回 true;否则返回 false</returns>
|
||||
public static bool ContainsChineseOptimized(this string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (char c in input)
|
||||
{
|
||||
if (c >= '\u4e00' && c <= '\u9fa5')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user