EntityMapper 高性能实体映射工具
public static class EntityMapper
{
#region 配置和缓存
public class MapperConfig
{
public bool IgnoreNullValues { get; set; }
public Dictionary<string, string> PropertyAliases { get; } = new();
public static MapperConfig Default => new();
}
private static readonly ConcurrentDictionary<Type, PropertyInfo[]> _propertyCache = new();
private static readonly ConcurrentDictionary<string, Delegate> _mapperCache = new();
private static readonly ThreadLocal<Stack<object>> _mappingStack = new(() => new Stack<object>());
private static readonly ConcurrentDictionary<(Type, Type), Func<object, object>> _typeConverters = new();
private static readonly ConcurrentDictionary<Type, Func<object>> _activatorCache = new();
static EntityMapper()
{
// 注册默认类型转换器
RegisterConverter<int, long>(v => v);
RegisterConverter<long, int>(v => (int)v);
RegisterConverter<string, DateTime>(DateTime.Parse);
RegisterConverter<DateTime, string>(v => v.ToString("yyyy-MM-dd"));
RegisterConverter<string, Guid>(Guid.Parse);
RegisterConverter<Guid, string>(v => v.ToString());
}
#endregion
#region 公共API
/// <summary>注册自定义类型转换器</summary>
public static void RegisterConverter<TFrom, TTo>(Func<TFrom, TTo> converter)
{
_typeConverters[(typeof(TFrom), typeof(TTo))] = v => converter((TFrom)v);
// 自动支持可空类型转换
if (typeof(TFrom).IsValueType && !IsNullable(typeof(TFrom)))
{
var nullableFromType = typeof(Nullable<>).MakeGenericType(typeof(TFrom));
_typeConverters[(nullableFromType, typeof(TTo))] = v => v == null ? default : converter((TFrom)v);
}
}
/// <summary>对象映射</summary>
public static TTarget Map<TSource, TTarget>(
this TSource source,
TTarget target = default,
MapperConfig config = null) where TTarget : new()
{
if (source == null) return default;
config ??= MapperConfig.Default;
// 循环引用检测
if (_mappingStack.Value.Contains(source))
throw new InvalidOperationException($"检测到循环引用: {typeof(TSource)}");
_mappingStack.Value.Push(source);
try
{
target ??= CreateInstance<TTarget>();
GetMapper<TSource, TTarget>()(source, target, config);
return target;
}
catch (Exception ex)
{
throw new InvalidOperationException($"映射 {typeof(TSource)} → {typeof(TTarget)} 失败: {ex.Message}", ex);
}
finally
{
_mappingStack.Value.Pop();
}
}
/// <summary>批量映射</summary>
public static List<TTarget> MapList<TSource, TTarget>(
this IEnumerable<TSource> sources,
MapperConfig config = null) where TTarget : new()
{
if (sources == null) return null;
config ??= MapperConfig.Default;
var mapper = GetMapper<TSource, TTarget>();
var results = new List<TTarget>();
foreach (var source in sources)
{
var target = CreateInstance<TTarget>();
mapper(source, target, config);
results.Add(target);
}
return results;
}
#endregion
#region 核心映射逻辑
private static Action<TSource, TTarget, MapperConfig> GetMapper<TSource, TTarget>()
{
var cacheKey = $"{typeof(TSource)}->{typeof(TTarget)}";
return (Action<TSource, TTarget, MapperConfig>)_mapperCache.GetOrAdd(cacheKey, _ =>
{
var sourceParam = Expression.Parameter(typeof(TSource));
var targetParam = Expression.Parameter(typeof(TTarget));
var configParam = Expression.Parameter(typeof(MapperConfig));
var expressions = new List<Expression>();
foreach (var targetProp in typeof(TTarget).GetProperties().Where(p => p.CanWrite))
{
var sourceProp = FindSourceProperty<TSource>(targetProp.Name, configParam);
if (sourceProp == null) continue;
var sourceValue = Expression.Property(sourceParam, sourceProp);
var assignExpr = BuildPropertyAssignment(
sourceValue,
targetProp,
targetParam,
configParam);
if (assignExpr != null) expressions.Add(assignExpr);
}
// 修复:确保Block至少有一个表达式
var body = expressions.Count == 0
? Expression.Block(Expression.Empty()) // 使用空表达式块
: Expression.Block(expressions);
return Expression.Lambda<Action<TSource, TTarget, MapperConfig>>(
body, sourceParam, targetParam, configParam).Compile();
});
}
private static PropertyInfo FindSourceProperty<TSource>(
string targetPropName,
ParameterExpression configParam)
{
var props = _propertyCache.GetOrAdd(typeof(TSource),
t => t.GetProperties(BindingFlags.Public | BindingFlags.Instance));
// 模拟属性别名检查(实际运行时逻辑)
var config = new MapperConfig();
if (config.PropertyAliases.TryGetValue(targetPropName, out var sourcePropName))
{
return props.FirstOrDefault(p => p.Name == sourcePropName);
}
return props.FirstOrDefault(p => p.Name == targetPropName);
}
private static Expression BuildPropertyAssignment(
MemberExpression sourceValue,
PropertyInfo targetProp,
ParameterExpression targetParam,
ParameterExpression configParam)
{
var targetPropExpr = Expression.Property(targetParam, targetProp);
var ignoreNull = Expression.Property(configParam, nameof(MapperConfig.IgnoreNullValues));
// 优化后的null值表达式
Expression nullValue = sourceValue.Type.IsValueType && !IsNullable(sourceValue.Type)
? Expression.Default(sourceValue.Type)
: Expression.Constant(null, sourceValue.Type);
// 类型安全的null检查
var nullCheck = Expression.Equal(
sourceValue,
nullValue);
// 如果IgnoreNullValues为true且值为null,则跳过赋值
var condition = Expression.IfThen(
Expression.Not(Expression.AndAlso(ignoreNull, nullCheck)),
Expression.Assign(targetPropExpr,
BuildValueExpression(sourceValue, targetProp.PropertyType, configParam)));
return condition;
}
private static Expression BuildValueExpression(
Expression sourceValue,
Type targetType,
ParameterExpression configParam)
{
var sourceType = sourceValue.Type;
// 1. 类型相同直接赋值
if (sourceType == targetType) return sourceValue;
// 2. 处理可空类型转换
if (IsNullable(sourceType) || IsNullable(targetType))
{
var underlyingSourceType = Nullable.GetUnderlyingType(sourceType) ?? sourceType;
var underlyingTargetType = Nullable.GetUnderlyingType(targetType) ?? targetType;
if (underlyingSourceType == underlyingTargetType)
{
return Expression.Convert(sourceValue, targetType);
}
}
// 3. 使用注册的类型转换器
if (_typeConverters.TryGetValue((sourceType, targetType), out var converter))
{
return Expression.Convert(
Expression.Invoke(Expression.Constant(converter), sourceValue),
targetType);
}
// 4. 默认类型转换
return Expression.Convert(sourceValue, targetType);
}
#endregion
#region 辅助方法
private static T CreateInstance<T>() where T : new()
{
return _activatorCache.GetOrAdd(typeof(T), t =>
{
var newExpr = Expression.New(typeof(T));
var lambda = Expression.Lambda<Func<object>>(newExpr);
return lambda.Compile();
})() is T instance ? instance : new T();
}
private static bool IsNullable(Type type)
{
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
private static bool IsSimpleType(Type type)
{
return type.IsPrimitive
|| type.IsEnum
|| type == typeof(string)
|| type == typeof(decimal)
|| type == typeof(DateTime)
|| type == typeof(TimeSpan)
|| type == typeof(Guid);
}
#endregion
}
基于表达式树实现的高性能实体映射工具,支持嵌套对象、集合、类型转换和属性别名等功能
主要特性
- 高性能:使用表达式树编译委托,避免了反射的性能开销
- 线程安全:使用
ConcurrentDictionary和ThreadLocal保证线程安全 - 循环引用检测:通过栈结构检测并防止循环引用
- 类型转换支持:
- 内置常见类型转换(int/long, string/DateTime等)
- 支持自定义类型转换器注册
- 自动处理可空类型
- 灵活配置:
- 可忽略null值
- 支持属性别名映射
- 批量映射:支持集合类型的批量映射
核心实现
1. 缓存机制
_propertyCache:缓存类型的属性信息_mapperCache:缓存编译后的映射委托_typeConverters:缓存类型转换器_activatorCache:缓存对象创建委托
2. 映射流程
- 获取或创建映射委托(
GetMapper) - 为每个可写属性构建赋值表达式(
BuildPropertyAssignment) - 处理类型转换(
BuildValueExpression) - 编译表达式树为委托并执行
3. 表达式树构建
- 动态构建属性访问、类型检查和转换表达式
- 处理null值检查(考虑配置的
IgnoreNullValues) - 处理类型转换(包括注册的自定义转换器)
-
使用示例
-
// 注册自定义转换器 EntityMapper.RegisterConverter<string, int>(int.Parse); // 简单映射 var userDto = userEntity.Map<UserDto>(); // 批量映射 var orderDtos = orders.MapList<Order, OrderDto>(); // 使用配置 var config = new EntityMapper.MapperConfig { IgnoreNullValues = true, PropertyAliases = { ["DtoName"] = "EntityName" } }; var result = source.Map<Target>(config: config);

浙公网安备 33010602011771号