网站首页 网站源码

using System;
using System.Linq;
using System.Reflection;
using AutoMapper;
using MongoDB.Bson;
namespace Dpz.Core.Infrastructure.MapperConfig;
public class GlobalConfigMapper
{
private static readonly Lazy<GlobalConfigMapper> LazyMapper = new(() => new GlobalConfigMapper());
private GlobalConfigMapper()
{
Mapper = ConfigGlobalMapper();
}
public IMapper Mapper { get; }
public static GlobalConfigMapper GetInstance()
{
return LazyMapper.Value;
}
public static GlobalConfigMapper Instance => LazyMapper.Value;
private static IMapper ConfigGlobalMapper()
{
var types = Assembly.Load("Dpz.Core.Public.ViewModel").GetExportedTypes();
var config = new MapperConfigurationExpression();
// 1. 传统的 IMapFrom<T> 接口映射
ConfigureIMapFromMappings(types, config);
// 2. 静态接口映射
ConfigureStaticInterfaceMappings(types, config);
// 3. 基于特性的映射
ConfigureAttributeBasedMappings(types, config);
// 4. 内置映射规则
ConfigureBuiltInMappings(config);
var cfg = new MapperConfiguration(config);
IMapper mapper = new Mapper(cfg);
return mapper;
}
/// <summary>
/// 配置 IMapFrom 接口映射
/// </summary>
private static void ConfigureIMapFromMappings(
Type[] types,
MapperConfigurationExpression config
)
{
var maps =
from x in types
from y in x.GetInterfaces()
let faceType = y.GetTypeInfo()
where
faceType.IsGenericType
&& y.GetGenericTypeDefinition() == typeof(IMapFrom<>)
&& !x.IsAbstract
&& !x.IsInterface
select new { Source = y.GetGenericArguments()[0], Destination = x };
foreach (var item in maps)
{
config.CreateMap(item.Source, item.Destination);
config.CreateMap(item.Destination, item.Source);
}
}
/// <summary>
/// 配置静态接口映射(C# 11+)
/// </summary>
private static void ConfigureStaticInterfaceMappings(
Type[] types,
MapperConfigurationExpression config
)
{
var staticMappingTypes = types.Where(x =>
x.GetInterfaces().Any(i => i == typeof(IHaveCustomMapping))
&& x is { IsAbstract: false, IsInterface: false }
);
foreach (var type in staticMappingTypes)
{
// 调用静态方法
var method = type.GetMethod(
nameof(IHaveCustomMapping.CreateMappings),
BindingFlags.Static | BindingFlags.Public,
null,
[typeof(MapperConfigurationExpression)],
null
);
method?.Invoke(null, [config]);
}
}
/// <summary>
/// 配置基于特性的映射
/// </summary>
private static void ConfigureAttributeBasedMappings(
Type[] types,
MapperConfigurationExpression config
)
{
foreach (var type in types)
{
var mappingAttributes = type.GetCustomAttributes<AutoMappingAttribute>();
foreach (var attr in mappingAttributes)
{
attr.ConfigureMapping(config);
}
}
}
/// <summary>
/// 配置内置映射规则
/// </summary>
private static void ConfigureBuiltInMappings(MapperConfigurationExpression config)
{
config
.CreateMap<string, ObjectId>()
.ConstructUsing(
(x, _) =>
!string.IsNullOrEmpty(x) && ObjectId.TryParse(x, out var oid)
? oid
: ObjectId.Empty
);
}
}
上述代码定义了一个名为 GlobalConfigMapper 的类,主要用于配置和管理 AutoMapper 的映射规则。AutoMapper 是一个用于对象到对象映射的库,常用于将数据模型转换为视图模型或 DTO(数据传输对象)。以下是代码的主要功能和结构的详细解释:
GlobalConfigMapper 使用了单例模式,确保在整个应用程序中只有一个 GlobalConfigMapper 实例。通过 Lazy<T> 来延迟实例化,确保线程安全。
Lazy<GlobalConfigMapper> LazyMapper:使用 Lazy<T> 来延迟加载 GlobalConfigMapper 实例。GetInstance() 和 Instance 属性:提供获取单例实例的方法。在构造函数中,调用 ConfigGlobalMapper() 方法来配置 AutoMapper 的映射规则,并将其赋值给 Mapper 属性。
ConfigGlobalMapper() 方法负责加载类型并配置映射规则。它执行以下步骤:
Dpz.Core.Public.ViewModel 程序集中获取所有导出的类型。ConfigureIMapFromMappings() 方法,处理实现了 IMapFrom<T> 接口的类型。ConfigureStaticInterfaceMappings() 方法,处理实现了 IHaveCustomMapping 接口的类型,并调用其静态方法 CreateMappings。ConfigureAttributeBasedMappings() 方法,处理带有 AutoMappingAttribute 特性的类型,并调用其 ConfigureMapping 方法。ConfigureBuiltInMappings() 方法,设置一些内置的映射规则,例如将 string 转换为 ObjectId。IMapFrom<T> 接口的类型,并为源类型和目标类型创建双向映射。IHaveCustomMapping 接口的类型,并调用其静态方法 CreateMappings 来配置映射。AutoMappingAttribute 特性的类型,并调用其 ConfigureMapping 方法来配置映射。ObjectId。GlobalConfigMapper 类的主要目的是集中管理 AutoMapper 的配置,提供灵活的映射规则,支持多种映射方式(接口、静态方法、特性等),并确保在整个应用程序中使用相同的映射配置。通过这种方式,开发人员可以轻松地进行对象之间的转换,减少手动映射的工作量。
