From b89031b671450d2f9b3f9ced48179922bcfa29a6 Mon Sep 17 00:00:00 2001 From: maliming Date: Sat, 2 Aug 2025 10:35:47 +0800 Subject: [PATCH] Add `ObjectMappingHelper` to enhance performance. --- .../MapperlyAutoObjectMappingProvider.cs | 2 +- .../Abp/ObjectMapping/DefaultObjectMapper.cs | 59 +------------ .../Abp/ObjectMapping/ObjectMappingHelper.cs | 85 +++++++++++++++++++ 3 files changed, 87 insertions(+), 59 deletions(-) create mode 100644 framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/ObjectMappingHelper.cs diff --git a/framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapperlyAutoObjectMappingProvider.cs b/framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapperlyAutoObjectMappingProvider.cs index a3a9abc234..677649b79a 100644 --- a/framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapperlyAutoObjectMappingProvider.cs +++ b/framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapperlyAutoObjectMappingProvider.cs @@ -98,7 +98,7 @@ public class MapperlyAutoObjectMappingProvider : IAutoObjectMappingProvider protected virtual bool TryToMapCollection(TSource source, TDestination? destination, out TDestination collectionResult) { - if (!DefaultObjectMapper.IsCollectionGenericType(out var sourceArgumentType, out var destinationArgumentType, out var definitionGenericType)) + if (!ObjectMappingHelper.IsCollectionGenericType(out var sourceArgumentType, out var destinationArgumentType, out var definitionGenericType)) { collectionResult = default!; return false; diff --git a/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/DefaultObjectMapper.cs b/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/DefaultObjectMapper.cs index 6b0e723fbb..faf8c4e258 100644 --- a/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/DefaultObjectMapper.cs +++ b/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/DefaultObjectMapper.cs @@ -123,7 +123,7 @@ public class DefaultObjectMapper : IObjectMapper, ITransientDependency protected virtual bool TryToMapCollection(IServiceScope serviceScope, TSource source, TDestination? destination, out TDestination collectionResult) { - if (!IsCollectionGenericType(out var sourceArgumentType, out var destinationArgumentType, out var definitionGenericType)) + if (!ObjectMappingHelper.IsCollectionGenericType(out var sourceArgumentType, out var destinationArgumentType, out var definitionGenericType)) { collectionResult = default!; return false; @@ -242,63 +242,6 @@ public class DefaultObjectMapper : IObjectMapper, ITransientDependency return Expression.Lambda>(callConvert, instanceParam, sourceParam, destinationParam).Compile(); } - public static bool IsCollectionGenericType(out Type sourceArgumentType, out Type destinationArgumentType, out Type definitionGenericType) - { - sourceArgumentType = null!; - destinationArgumentType = null!; - definitionGenericType = null!; - - if ((!typeof(TSource).IsGenericType && !typeof(TSource).IsArray) || - (!typeof(TDestination).IsGenericType && !typeof(TDestination).IsArray)) - { - return false; - } - - var supportedCollectionTypes = new[] - { - typeof(IEnumerable<>), - typeof(ICollection<>), - typeof(Collection<>), - typeof(IList<>), - typeof(List<>) - }; - - if (typeof(TSource).IsGenericType && supportedCollectionTypes.Any(x => x == typeof(TSource).GetGenericTypeDefinition())) - { - sourceArgumentType = typeof(TSource).GenericTypeArguments[0]; - } - - if (typeof(TSource).IsArray) - { - sourceArgumentType = typeof(TSource).GetElementType()!; - } - - if (sourceArgumentType == null!) - { - return false; - } - - definitionGenericType = typeof(List<>); - if (typeof(TDestination).IsGenericType && supportedCollectionTypes.Any(x => x == typeof(TDestination).GetGenericTypeDefinition())) - { - destinationArgumentType = typeof(TDestination).GenericTypeArguments[0]; - - if (typeof(TDestination).GetGenericTypeDefinition() == typeof(ICollection<>) || - typeof(TDestination).GetGenericTypeDefinition() == typeof(Collection<>)) - { - definitionGenericType = typeof(Collection<>); - } - } - - if (typeof(TDestination).IsArray) - { - destinationArgumentType = typeof(TDestination).GetElementType()!; - definitionGenericType = typeof(Array); - } - - return destinationArgumentType != null!; - } - protected virtual TDestination AutoMap(object source) { return AutoObjectMappingProvider.Map(source); diff --git a/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/ObjectMappingHelper.cs b/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/ObjectMappingHelper.cs new file mode 100644 index 0000000000..cbfd33988b --- /dev/null +++ b/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/ObjectMappingHelper.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; + +namespace Volo.Abp.ObjectMapping; + +public static class ObjectMappingHelper +{ + private static readonly ConcurrentDictionary<(Type, Type), (Type sourceArgumentType, Type destinationArgumentType, Type definitionGenericType)?> Cache = new(); + + public static bool IsCollectionGenericType( + out Type sourceArgumentType, + out Type destinationArgumentType, + out Type definitionGenericType) + { + var cached = Cache.GetOrAdd((typeof(TSource), typeof(TDestination)), _ => IsCollectionGenericTypeInternal()); + if (cached == null) + { + sourceArgumentType = destinationArgumentType = definitionGenericType = null!; + return false; + } + + (sourceArgumentType, destinationArgumentType, definitionGenericType) = cached.Value; + return true; + } + + private static (Type, Type, Type)? IsCollectionGenericTypeInternal() + { + Type sourceArgumentType = null!; + Type destinationArgumentType = null!; + Type definitionGenericType = null!; + + if ((!typeof(TSource).IsGenericType && !typeof(TSource).IsArray) || + (!typeof(TDestination).IsGenericType && !typeof(TDestination).IsArray)) + { + return null; + } + + var supportedCollectionTypes = new[] + { + typeof(IEnumerable<>), + typeof(ICollection<>), + typeof(Collection<>), + typeof(IList<>), + typeof(List<>) + }; + + if (typeof(TSource).IsGenericType && supportedCollectionTypes.Any(x => x == typeof(TSource).GetGenericTypeDefinition())) + { + sourceArgumentType = typeof(TSource).GenericTypeArguments[0]; + } + + if (typeof(TSource).IsArray) + { + sourceArgumentType = typeof(TSource).GetElementType()!; + } + + if (sourceArgumentType == null) + { + return null; + } + + definitionGenericType = typeof(List<>); + if (typeof(TDestination).IsGenericType && supportedCollectionTypes.Any(x => x == typeof(TDestination).GetGenericTypeDefinition())) + { + destinationArgumentType = typeof(TDestination).GenericTypeArguments[0]; + + if (typeof(TDestination).GetGenericTypeDefinition() == typeof(ICollection<>) || + typeof(TDestination).GetGenericTypeDefinition() == typeof(Collection<>)) + { + definitionGenericType = typeof(Collection<>); + } + } + + if (typeof(TDestination).IsArray) + { + destinationArgumentType = typeof(TDestination).GetElementType()!; + definitionGenericType = typeof(Array); + } + + return (sourceArgumentType, destinationArgumentType, definitionGenericType); + } +}