diff --git a/src/Umbraco.Core/Models/DeepCloneHelper.cs b/src/Umbraco.Core/Models/DeepCloneHelper.cs index d8ef10751b..eb3be9d145 100644 --- a/src/Umbraco.Core/Models/DeepCloneHelper.cs +++ b/src/Umbraco.Core/Models/DeepCloneHelper.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -27,6 +28,11 @@ namespace Umbraco.Core.Models public static class DeepCloneHelper { + /// + /// Used to avoid constant reflection (perf) + /// + private static readonly ConcurrentDictionary PropCache = new ConcurrentDictionary(); + /// /// Used to deep clone any reference properties on the object (should be done after a MemberwiseClone for which the outcome is 'output') /// @@ -43,16 +49,18 @@ namespace Umbraco.Core.Models throw new InvalidOperationException("Both the input and output types must be the same"); } - var refProperties = inputType.GetProperties() - .Where(x => - //is not attributed with the ignore clone attribute - x.GetCustomAttribute() == null - //reference type but not string - && x.PropertyType.IsValueType == false && x.PropertyType != typeof (string) - //settable - && x.CanWrite - //non-indexed - && x.GetIndexParameters().Any() == false); + var refProperties = PropCache.GetOrAdd(inputType, type => + inputType.GetProperties() + .Where(x => + //is not attributed with the ignore clone attribute + x.GetCustomAttribute() == null + //reference type but not string + && x.PropertyType.IsValueType == false && x.PropertyType != typeof (string) + //settable + && x.CanWrite + //non-indexed + && x.GetIndexParameters().Any() == false) + .ToArray()); foreach (var propertyInfo in refProperties) {