提交代码

This commit is contained in:
zpc 2024-11-01 16:59:39 +08:00
parent e067994af9
commit 9ca49db15c
8 changed files with 1276 additions and 200 deletions

View File

@ -16,6 +16,9 @@ using System.Reflection;
namespace CloudGaming.Code.AppExtend
{
/// <summary>
///
/// </summary>
public class CustomResultFilter : IResultFilter
{
private readonly IHttpContextAccessor _httpContextAccessor;
@ -37,22 +40,20 @@ namespace CloudGaming.Code.AppExtend
//Dictionary<string, object> keyValuePairs = new Dictionary<string, object>();
if (context.Result is ObjectResult objectResult && objectResult.Value != null)
{
//if (IsPrimitiveOrString(objectResult.Value.GetType()))
//{
//}
var dic = objectResult.Value.ToDictionaryOrList();
var t = objectResult.Value.GetType();
if (!t.FullName.Contains("HuanMeng.DotNetCore.Base.BaseResponse"))
var x = objectResult.Value.GetType();
object? value = null;
if (!x.FullName.Contains("HuanMeng.DotNetCore.Base.BaseResponse"))
{
BaseResponse<object> baseResponse = new BaseResponse<object>(ResonseCode.Success, "", dic);
objectResult.Value = baseResponse;
BaseResponse<object> baseResponse = new BaseResponse<object>(ResonseCode.Success, "", objectResult.Value);
value = baseResponse;
}
else
{
objectResult.Value = dic;
value = objectResult.Value;
}
var dic = value.ToDictionaryOrList();
objectResult.Value = dic;
//if (objectResult.Value is IEnumerable enumerable)
//{
// var list = objectResult.Value.ToListDictionary(5);

View File

@ -11,6 +11,7 @@
<ItemGroup>
<PackageReference Include="AgileConfig.Client" Version="1.7.3" />
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="FastMember" Version="1.5.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.10" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" />
</ItemGroup>

View File

@ -1,67 +0,0 @@
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<Type, PropertyInfo[]> PropertyCache = new();
private static readonly ConcurrentDictionary<Type, FieldInfo[]> FieldCache = new();
public static Dictionary<string, object> ToDictionary(this object obj, int maxDepth = 3)
{
return ToDictionaryRecursive(obj, maxDepth);
}
private static Dictionary<string, object> ToDictionaryRecursive(object obj, int depth)
{
if (obj == null || depth < 0)
return null;
var dictionary = new Dictionary<string, object>();
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<object>();
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;
}
}

View File

@ -1,24 +1,66 @@
// See https://aka.ms/new-console-template for more information
using CloudGaming.DtoModel;
using CloudGaming.Test;
using HuanMeng.DotNetCore.Utility;
using Newtonsoft.Json;
using System.Reflection;
Console.WriteLine("Hello, World!");
AppConfigDto appConfigDto = new AppConfigDto()
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
using CloudGaming.DtoModel.Epg;
namespace CloudGaming.Test
{
//AppConfigExtend = new AppConfigExtend()
//{
// TestImage = 1
//},
//CheckingGames = new List<string>() { "iu","cg111"},
//IsChecking = true,
//HighDelay = true,
//OpenImage = 1,
//MyProperty = "test"
};
var dic = appConfigDto.ToDictionary(15);
Console.WriteLine(JsonConvert.SerializeObject(dic));
Console.ReadKey();
[MemoryDiagnoser]
[MarkdownExporterAttribute.GitHub]
[SimpleJob(RuntimeMoniker.Net80, baseline: true)]
[RPlotExporter]
public class Program
{
static void Main(string[] args)
{
//List<EpgCategoryDto> epgCategoryDtos = new List<EpgCategoryDto>();
//for (int i = 0; i < 20; i++)
//{
// epgCategoryDtos.Add(new EpgCategoryDto()
// {
// CategoryName = "Banner" + i,
// CategoryType = "Banner" + i,
// IsQuickStartPopUp = true,
// ShowNum_Index = 10 + i,
// EpgList = new List<EpgInfo>()
// {
// new EpgInfo(){
// CornerIcon=i,
// EpgId=i,
// IdName="IO"+i,
// ResType=4,
// Pic=1,
// Title="title"+i
// },
// new EpgInfo(){
// CornerIcon=i+2,
// EpgId=i+2,
// IdName="IO"+i+2,
// ResType=4+2,
// Pic=2,
// Title="title"+i+2
// }
// },
// });
//}
//var dic = ObjectExtensions5.ToDictionaryOrList(epgCategoryDtos);
//Console.WriteLine(JsonConvert.SerializeObject(dic));
BenchmarkRunner.Run<ToDictionaryOrListTest>();
}
}
}

View File

@ -0,0 +1,478 @@
using BenchmarkDotNet.Attributes;
using CloudGaming.DtoModel;
using CloudGaming.DtoModel.Epg;
using HuanMeng.DotNetCore.Utility;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudGaming.Test
{
[MemoryDiagnoser]
public class ToDictionaryOrListTest
{
public ToDictionaryOrListTest()
{
}
//[Benchmark]
public object ObjectToDictionaryOrListTest1()
{
EpgCategoryDto epgCategoryDto = new EpgCategoryDto()
{
CategoryName = "Banner",
CategoryType = "Banner",
IsQuickStartPopUp = true,
ShowNum_Index = 10,
EpgList = new List<EpgInfo>()
{
new EpgInfo(){
CornerIcon=10,
EpgId=10,
IdName="IO",
ResType=4,
Title="title"
}
},
};
var dic = epgCategoryDto.ToDictionaryOrList();
return dic;
}
//[Benchmark]
public object ListToDictionaryOrListTest1()
{
List<EpgCategoryDto> epgCategoryDtos = new List<EpgCategoryDto>();
for (int i = 0; i < 20; i++)
{
epgCategoryDtos.Add(new EpgCategoryDto()
{
CategoryName = "Banner" + i,
CategoryType = "Banner" + i,
IsQuickStartPopUp = true,
ShowNum_Index = 10 + i,
EpgList = new List<EpgInfo>()
{
new EpgInfo(){
CornerIcon=i,
EpgId=i,
IdName="IO"+i,
ResType=4,
Title="title"+i
},
new EpgInfo(){
CornerIcon=i+2,
EpgId=i+2,
IdName="IO"+i+2,
ResType=4+2,
Title="title"+i+2
}
},
});
}
var dic = epgCategoryDtos.ToDictionaryOrList();
return dic;
}
//[Benchmark]
public object ObjectToDictionaryOrListExtend1()
{
EpgCategoryDto epgCategoryDto = new EpgCategoryDto()
{
CategoryName = "Banner",
CategoryType = "Banner",
IsQuickStartPopUp = true,
ShowNum_Index = 10,
EpgList = new List<EpgInfo>()
{
new EpgInfo(){
CornerIcon=10,
EpgId=10,
IdName="IO",
ResType=4,
Title="title"
}
},
};
var dic = ObjectExtensions1.ToDictionaryOrList(epgCategoryDto);
return dic;
}
//[Benchmark]
public object ListToDictionaryOrListExtend1()
{
List<EpgCategoryDto> epgCategoryDtos = new List<EpgCategoryDto>();
for (int i = 0; i < 20; i++)
{
epgCategoryDtos.Add(new EpgCategoryDto()
{
CategoryName = "Banner" + i,
CategoryType = "Banner" + i,
IsQuickStartPopUp = true,
ShowNum_Index = 10 + i,
EpgList = new List<EpgInfo>()
{
new EpgInfo(){
CornerIcon=i,
EpgId=i,
IdName="IO"+i,
ResType=4,
Title="title"+i
},
new EpgInfo(){
CornerIcon=i+2,
EpgId=i+2,
IdName="IO"+i+2,
ResType=4+2,
Title="title"+i+2
}
},
});
}
var dic = ObjectExtensions1.ToDictionaryOrList(epgCategoryDtos);
return dic;
}
//[Benchmark]
public object ObjectToDictionaryOrListExtend3()
{
EpgCategoryDto epgCategoryDto = new EpgCategoryDto()
{
CategoryName = "Banner",
CategoryType = "Banner",
IsQuickStartPopUp = true,
ShowNum_Index = 10,
EpgList = new List<EpgInfo>()
{
new EpgInfo(){
CornerIcon=10,
EpgId=10,
IdName="IO",
ResType=4,
Title="title"
}
},
};
var dic = ObjectExtensions3.ToDictionaryOrList(epgCategoryDto);
return dic;
}
//[Benchmark]
public object ListToDictionaryOrListExtend3()
{
List<EpgCategoryDto> epgCategoryDtos = new List<EpgCategoryDto>();
for (int i = 0; i < 20; i++)
{
epgCategoryDtos.Add(new EpgCategoryDto()
{
CategoryName = "Banner" + i,
CategoryType = "Banner" + i,
IsQuickStartPopUp = true,
ShowNum_Index = 10 + i,
EpgList = new List<EpgInfo>()
{
new EpgInfo(){
CornerIcon=i,
EpgId=i,
IdName="IO"+i,
ResType=4,
Title="title"+i
},
new EpgInfo(){
CornerIcon=i+2,
EpgId=i+2,
IdName="IO"+i+2,
ResType=4+2,
Title="title"+i+2
}
},
});
}
var dic = ObjectExtensions3.ToDictionaryOrList(epgCategoryDtos);
return dic;
}
[Benchmark]
public object ObjectToDictionaryOrListExtend4()
{
EpgCategoryDto epgCategoryDto = new EpgCategoryDto()
{
CategoryName = "Banner",
CategoryType = "Banner",
IsQuickStartPopUp = true,
ShowNum_Index = 10,
EpgList = new List<EpgInfo>()
{
new EpgInfo(){
CornerIcon=10,
EpgId=10,
IdName="IO",
ResType=4,
Title="title"
}
},
};
var dic = ObjectExtensions5.ToDictionaryOrList(epgCategoryDto);
return dic;
}
[Benchmark]
public object ListToDictionaryOrListExtend4()
{
List<EpgCategoryDto> epgCategoryDtos = new List<EpgCategoryDto>();
for (int i = 0; i < 20; i++)
{
epgCategoryDtos.Add(new EpgCategoryDto()
{
CategoryName = "Banner" + i,
CategoryType = "Banner" + i,
IsQuickStartPopUp = true,
ShowNum_Index = 10 + i,
EpgList = new List<EpgInfo>()
{
new EpgInfo(){
CornerIcon=i,
EpgId=i,
IdName="IO"+i,
ResType=4,
Title="title"+i
},
new EpgInfo(){
CornerIcon=i+2,
EpgId=i+2,
IdName="IO"+i+2,
ResType=4+2,
Title="title"+i+2
}
},
});
}
var dic = ObjectExtensions5.ToDictionaryOrList(epgCategoryDtos);
return dic;
}
[Benchmark]
public object ObjectToDictionaryOrListExtend6()
{
EpgCategoryDto epgCategoryDto = new EpgCategoryDto()
{
CategoryName = "Banner",
CategoryType = "Banner",
IsQuickStartPopUp = true,
ShowNum_Index = 10,
EpgList = new List<EpgInfo>()
{
new EpgInfo(){
CornerIcon=10,
EpgId=10,
IdName="IO",
ResType=4,
Title="title"
}
},
};
var dic = ObjectExtensions6.ToDictionaryOrList(epgCategoryDto);
return dic;
}
[Benchmark]
public object ListToDictionaryOrListExtend6()
{
List<EpgCategoryDto> epgCategoryDtos = new List<EpgCategoryDto>();
for (int i = 0; i < 20; i++)
{
epgCategoryDtos.Add(new EpgCategoryDto()
{
CategoryName = "Banner" + i,
CategoryType = "Banner" + i,
IsQuickStartPopUp = true,
ShowNum_Index = 10 + i,
EpgList = new List<EpgInfo>()
{
new EpgInfo(){
CornerIcon=i,
EpgId=i,
IdName="IO"+i,
ResType=4,
Title="title"+i
},
new EpgInfo(){
CornerIcon=i+2,
EpgId=i+2,
IdName="IO"+i+2,
ResType=4+2,
Title="title"+i+2
}
},
});
}
var dic = ObjectExtensions6.ToDictionaryOrList(epgCategoryDtos);
return dic;
}
[Benchmark]
public object ObjectToDictionaryOrListExtend7()
{
EpgCategoryDto epgCategoryDto = new EpgCategoryDto()
{
CategoryName = "Banner",
CategoryType = "Banner",
IsQuickStartPopUp = true,
ShowNum_Index = 10,
EpgList = new List<EpgInfo>()
{
new EpgInfo(){
CornerIcon=10,
EpgId=10,
IdName="IO",
ResType=4,
Title="title"
}
},
};
var dic = ObjectExtensions6.ToDictionaryOrList(epgCategoryDto);
return dic;
}
[Benchmark]
public object ListToDictionaryOrListExtend7()
{
List<EpgCategoryDto> epgCategoryDtos = new List<EpgCategoryDto>();
for (int i = 0; i < 20; i++)
{
epgCategoryDtos.Add(new EpgCategoryDto()
{
CategoryName = "Banner" + i,
CategoryType = "Banner" + i,
IsQuickStartPopUp = true,
ShowNum_Index = 10 + i,
EpgList = new List<EpgInfo>()
{
new EpgInfo(){
CornerIcon=i,
EpgId=i,
IdName="IO"+i,
ResType=4,
Title="title"+i
},
new EpgInfo(){
CornerIcon=i+2,
EpgId=i+2,
IdName="IO"+i+2,
ResType=4+2,
Title="title"+i+2
}
},
});
}
var dic = ObjectExtensions7.ToDictionaryOrList(epgCategoryDtos);
return dic;
}
[Benchmark]
public object ObjectToDictionaryOrListExtend8()
{
EpgCategoryDto epgCategoryDto = new EpgCategoryDto()
{
CategoryName = "Banner",
CategoryType = "Banner",
IsQuickStartPopUp = true,
ShowNum_Index = 10,
EpgList = new List<EpgInfo>()
{
new EpgInfo(){
CornerIcon=10,
EpgId=10,
IdName="IO",
ResType=4,
Title="title"
}
},
};
var dic = ObjectExtensions.ToDictionaryOrList(epgCategoryDto);
return dic;
}
[Benchmark]
public object ListToDictionaryOrListExtend8()
{
List<EpgCategoryDto> epgCategoryDtos = new List<EpgCategoryDto>();
for (int i = 0; i < 20; i++)
{
epgCategoryDtos.Add(new EpgCategoryDto()
{
CategoryName = "Banner" + i,
CategoryType = "Banner" + i,
IsQuickStartPopUp = true,
ShowNum_Index = 10 + i,
EpgList = new List<EpgInfo>()
{
new EpgInfo(){
CornerIcon=i,
EpgId=i,
IdName="IO"+i,
ResType=4,
Title="title"+i
},
new EpgInfo(){
CornerIcon=i+2,
EpgId=i+2,
IdName="IO"+i+2,
ResType=4+2,
Title="title"+i+2
}
},
});
}
var dic = ObjectExtensions.ToDictionaryOrList(epgCategoryDtos);
return dic;
}
}
}

View File

@ -1,4 +1,4 @@
using System;
using System;
namespace CloudGaming.Model.DbSqlServer.Db_Phone;

View File

@ -1,105 +0,0 @@
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;
using Newtonsoft.Json.Linq;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace HuanMeng.DotNetCore.Utility;
public static class ObjectExtensions
{
/// <summary>
/// 缓存属性信息以提高反射访问的性能,使用 ConcurrentDictionary 确保线程安全
/// </summary>
private static readonly ConcurrentDictionary<Type, PropertyInfo[]> PropertyCache = new();
/// <summary>
/// 缓存字段信息以提高反射访问的性能,使用 ConcurrentDictionary 确保线程安全
/// </summary>
private static readonly ConcurrentDictionary<Type, FieldInfo[]> FieldCache = new();
/// <summary>
/// 判断对象是否为基础类型。
/// </summary>
public static bool IsPrimitiveType(object obj)
{
if (obj == null) return false;
Type type = obj.GetType();
return type.IsPrimitive || type.IsValueType || type == typeof(string);
}
/// <summary>
/// 判断对象是否为集合类型(排除字符串)。
/// </summary>
public static bool IsCollectionType(object obj)
{
if (obj == null) return false;
return obj is IEnumerable && !(obj is string);
}
/// <summary>
/// 判断对象是否为复杂类型。
/// </summary>
public static bool IsComplexType(object obj)
{
if (obj == null) return false;
Type type = obj.GetType();
// 非基础类型且非集合类型的对象即为复杂类型
return !IsPrimitiveType(obj) && !IsCollectionType(obj);
}
public static object ToDictionaryOrList(this object obj)
{
if (obj == null)
{
return null;
}
Type type = obj.GetType();
//判断对象是否是基础类型的
if (type.IsPrimitive || type.IsValueType || type == typeof(string))
{
return type;
}
//判断对象是否是数组类型的
else if (obj is IEnumerable enumerable && !(obj is string))
{
List<object> list = new List<object>();
foreach (var item in enumerable)
{
list.Add(ToDictionaryOrList(item));
}
return list;
}
else
{
//object类型
Dictionary<string, object> keyValuePairs = new Dictionary<string, object>();
var properties = PropertyCache.GetOrAdd(type, t => t.GetProperties(BindingFlags.Public | BindingFlags.Instance));
foreach (var property in properties)
{
var imagesAttribute = property.GetCustomAttribute<ImagesAttribute>();
var objstr = property.GetValue(obj);
//对象中判断字段是否是数组
if (objstr is IEnumerable enumerable1 && !(objstr is string))
{
keyValuePairs[property.Name] = ToDictionaryOrList(objstr);
continue;
}
keyValuePairs[property.Name] = objstr;
}
return keyValuePairs;
}
}
}

View File

@ -0,0 +1,726 @@
using System;
using System.Collections.Concurrent;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using HuanMeng.DotNetCore.AttributeExtend;
using System.Linq.Expressions;
namespace HuanMeng.DotNetCore.Utility;
/// <summary>
///
/// </summary>
public static class ObjectExtensions
{
/// <summary>
/// 线程安全的缓存,用于存储每个类型的属性访问器数组
/// </summary>
private static readonly ConcurrentDictionary<Type, PropertyAccessor[]> PropertyCache = new();
/// <summary>
/// 缓存每个属性是否具有 ImagesAttribute 特性
/// </summary>
public static readonly ConcurrentDictionary<PropertyInfo, bool> _PropertyCache = new();
/// <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(this 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)
{
// 递归调用 ToDictionaryOrList 对集合中的每个项进行转换
list.Add(ToDictionaryOrList(item));
}
return list;
}
/// <summary>
/// 将对象的属性转换为字典
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
private static Dictionary<string, object> TransformObject(object obj, string prefix = "")
{
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);
// 如果属性值是字符串类型,添加 "test" 前缀
if (propertyValue is string stringValue)
{
//propertyValue =;
keyValuePairs[accessor.PropertyName] = $"test{stringValue}";
continue;
}
// 如果属性有 ImagesAttribute 特性,值前面加上 "image" 前缀
// 否则,如果属性是集合类型,递归转换
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 =>
{
// 创建属性的 Getter 委托
var getter = CreatePropertyGetter(type, property);
// 使用缓存检查属性是否具有 ImagesAttribute 特性
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)); // 转换属性值为 object
return Expression.Lambda<Func<object, object>>(convertPropertyAccess, parameter).Compile(); // 编译为委托
}
// 属性访问器类包含属性名、Getter 和特性标志
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 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;
}
}
}