1
1
using System ;
2
2
using System . Collections ;
3
+ using System . Collections . Concurrent ;
3
4
using System . Collections . Generic ;
4
5
using System . Linq ;
5
6
using System . Reflection ;
@@ -27,6 +28,11 @@ internal class DoNotCloneAttribute : Attribute
27
28
28
29
public static class DeepCloneHelper
29
30
{
31
+ /// <summary>
32
+ /// Used to avoid constant reflection (perf)
33
+ /// </summary>
34
+ private static readonly ConcurrentDictionary < Type , PropertyInfo [ ] > PropCache = new ConcurrentDictionary < Type , PropertyInfo [ ] > ( ) ;
35
+
30
36
/// <summary>
31
37
/// Used to deep clone any reference properties on the object (should be done after a MemberwiseClone for which the outcome is 'output')
32
38
/// </summary>
@@ -43,16 +49,18 @@ public static void DeepCloneRefProperties(IDeepCloneable input, IDeepCloneable o
43
49
throw new InvalidOperationException ( "Both the input and output types must be the same" ) ;
44
50
}
45
51
46
- var refProperties = inputType . GetProperties ( )
47
- . Where ( x =>
48
- //is not attributed with the ignore clone attribute
52
+ var refProperties = PropCache . GetOrAdd ( inputType , type =>
53
+ inputType . GetProperties ( )
54
+ . Where ( x =>
55
+ //is not attributed with the ignore clone attribute
49
56
Attribute . GetCustomAttribute ( x , typeof ( DoNotCloneAttribute ) ) == null
50
- //reference type but not string
51
- && x . PropertyType . IsValueType == false && x . PropertyType != typeof ( string )
52
- //settable
53
- && x . CanWrite
54
- //non-indexed
55
- && x . GetIndexParameters ( ) . Any ( ) == false ) ;
57
+ //reference type but not string
58
+ && x . PropertyType . IsValueType == false && x . PropertyType != typeof ( string )
59
+ //settable
60
+ && x . CanWrite
61
+ //non-indexed
62
+ && x . GetIndexParameters ( ) . Any ( ) == false )
63
+ . ToArray ( ) ) ;
56
64
57
65
foreach ( var propertyInfo in refProperties )
58
66
{
0 commit comments