提交代码
This commit is contained in:
parent
e067994af9
commit
9ca49db15c
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
|
||||
namespace CloudGaming.Model.DbSqlServer.Db_Phone;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user