44using System . Linq . Expressions ;
55using System . Reflection ;
66using System . ComponentModel ;
7+ using SmartStore . Utilities . Reflection ;
8+ using SmartStore . Utilities ;
9+ using System . Collections . Concurrent ;
710
811namespace SmartStore
912{
@@ -13,26 +16,9 @@ namespace SmartStore
1316 [ Serializable ]
1417 public abstract class ComparableObject
1518 {
16- /// <summary>
17- /// To help ensure hashcode uniqueness, a carefully selected random number multiplier
18- /// is used within the calculation. Goodrich and Tamassia's Data Structures and
19- /// Algorithms in Java asserts that 31, 33, 37, 39 and 41 will produce the fewest number
20- /// of collissions. See http://computinglife.wordpress.com/2008/11/20/why-do-hash-functions-use-prime-numbers/
21- /// for more information.
22- /// </summary>
23- protected const int HashMultiplier = 31 ;
24-
25- private readonly List < PropertyInfo > _extraSignatureProperties = new List < PropertyInfo > ( ) ;
19+ private readonly HashSet < string > _extraSignatureProperties = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) ;
2620
27- /// <summary>
28- /// This static member caches the domain signature properties to avoid looking them up for
29- /// each instance of the same type.
30- ///
31- /// A description of the ThreadStatic attribute may be found at
32- /// http://www.dotnetjunkies.com/WebLog/chris.taylor/archive/2005/08/18/132026.aspx
33- /// </summary>
34- [ ThreadStatic ]
35- private static IDictionary < Type , IEnumerable < PropertyInfo > > s_signatureProperties ;
21+ private static readonly ConcurrentDictionary < Type , string [ ] > _signaturePropertyNames = new ConcurrentDictionary < Type , string [ ] > ( ) ;
3622
3723 public override bool Equals ( object obj )
3824 {
@@ -58,21 +44,23 @@ public override int GetHashCode()
5844 var signatureProperties = GetSignatureProperties ( ) ;
5945 Type t = this . GetType ( ) ;
6046
61- // It's possible for two objects to return the same hash code based on
62- // identically valued properties, even if they're of two different types,
63- // so we include the object's type in the hash calculation
64- int hashCode = t . GetHashCode ( ) ;
47+ var combiner = HashCodeCombiner . Start ( ) ;
6548
66- foreach ( var pi in signatureProperties )
49+ // It's possible for two objects to return the same hash code based on
50+ // identically valued properties, even if they're of two different types,
51+ // so we include the object's type in the hash calculation
52+ combiner . Add ( t . GetHashCode ( ) ) ;
53+
54+ foreach ( var prop in signatureProperties )
6755 {
68- object value = pi . GetValue ( this ) ;
56+ object value = prop . GetValue ( this ) ;
6957
7058 if ( value != null )
71- hashCode = ( hashCode * HashMultiplier ) ^ value . GetHashCode ( ) ;
59+ combiner . Add ( value . GetHashCode ( ) ) ;
7260 }
7361
7462 if ( signatureProperties . Any ( ) )
75- return hashCode ;
63+ return combiner . CombinedHash ;
7664
7765 // If no properties were flagged as being part of the signature of the object,
7866 // then simply return the hashcode of the base object as the hashcode.
@@ -121,56 +109,46 @@ protected virtual bool HasSameSignatureAs(ComparableObject compareTo)
121109
122110 /// <summary>
123111 /// </summary>
124- public IEnumerable < PropertyInfo > GetSignatureProperties ( )
112+ public IEnumerable < FastProperty > GetSignatureProperties ( )
125113 {
126- IEnumerable < PropertyInfo > properties ;
127-
128- // Init the signaturePropertiesDictionary here due to reasons described at
129- // http://blogs.msdn.com/jfoscoding/archive/2006/07/18/670497.aspx
130- if ( s_signatureProperties == null )
131- s_signatureProperties = new Dictionary < Type , IEnumerable < PropertyInfo > > ( ) ;
132-
133- var t = GetType ( ) ;
134-
135- if ( s_signatureProperties . TryGetValue ( t , out properties ) )
136- return properties ;
137-
138- return ( s_signatureProperties [ t ] = GetSignaturePropertiesCore ( ) ) ;
114+ var type = GetType ( ) ;
115+ var propertyNames = GetSignaturePropertyNamesCore ( ) ;
116+
117+ foreach ( var name in propertyNames )
118+ {
119+ var fastProperty = FastProperty . GetProperty ( type , name ) ;
120+ if ( fastProperty != null )
121+ {
122+ yield return fastProperty ;
123+ }
124+ }
139125 }
140126
141127 /// <summary>
142128 /// Enforces the template method pattern to have child objects determine which specific
143129 /// properties should and should not be included in the object signature comparison.
144130 /// </summary>
145- protected virtual IEnumerable < PropertyInfo > GetSignaturePropertiesCore ( )
131+ protected virtual string [ ] GetSignaturePropertyNamesCore ( )
146132 {
147- Type t = this . GetType ( ) ;
148- //var properties = TypeDescriptor.GetProvider(t).GetTypeDescriptor(t)
149- // .GetPropertiesWith<ObjectSignatureAttribute>();
133+ Type type = this . GetType ( ) ;
134+ string [ ] names ;
150135
151- //if (_extraSignatureProperties.Count > 0)
152- //{
153- // properties = properties.Union(_extraSignatureProperties);
154- //}
136+ if ( ! _signaturePropertyNames . TryGetValue ( type , out names ) )
137+ {
138+ names = type . GetProperties ( BindingFlags . Public | BindingFlags . Instance )
139+ . Where ( p => Attribute . IsDefined ( p , typeof ( ObjectSignatureAttribute ) , true ) )
140+ . Select ( p => p . Name )
141+ . ToArray ( ) ;
155142
156- //return new PropertyDescriptorCollection(properties.ToArray(), true);
143+ _signaturePropertyNames . TryAdd ( type , names ) ;
144+ }
157145
158- var properties = t . GetProperties ( )
159- . Where ( p => Attribute . IsDefined ( p , typeof ( ObjectSignatureAttribute ) , true ) ) ;
146+ if ( _extraSignatureProperties . Count == 0 )
147+ {
148+ return names ;
149+ }
160150
161- return properties . Union ( _extraSignatureProperties ) . ToList ( ) ;
162- }
163-
164- /// <summary>
165- /// Adds an extra property to the type specific signature properties list.
166- /// </summary>
167- /// <param name="propertyInfo">The property to add.</param>
168- /// <remarks>Both lists are <c>unioned</c>, so
169- /// that no duplicates can occur within the global descriptor collection.</remarks>
170- protected void RegisterSignatureProperty ( PropertyInfo propertyInfo )
171- {
172- Guard . ArgumentNotNull ( ( ) => propertyInfo ) ;
173- _extraSignatureProperties . Add ( propertyInfo ) ;
151+ return names . Union ( _extraSignatureProperties ) . ToArray ( ) ;
174152 }
175153
176154 /// <summary>
@@ -183,13 +161,7 @@ protected void RegisterSignatureProperty(string propertyName)
183161 {
184162 Guard . ArgumentNotEmpty ( ( ) => propertyName ) ;
185163
186- Type t = GetType ( ) ;
187-
188- var pi = t . GetProperty ( propertyName , BindingFlags . Public | BindingFlags . Instance ) ;
189- if ( pi == null )
190- throw Error . Argument ( "propertyName" , "Could not find property '{0}' on type '{1}'." , propertyName , t ) ;
191-
192- RegisterSignatureProperty ( pi ) ;
164+ _extraSignatureProperties . Add ( propertyName ) ;
193165 }
194166
195167 }
@@ -212,7 +184,7 @@ protected void RegisterSignatureProperty(Expression<Func<T, object>> expression)
212184 {
213185 Guard . ArgumentNotNull ( ( ) => expression ) ;
214186
215- base . RegisterSignatureProperty ( expression . ExtractPropertyInfo ( ) ) ;
187+ base . RegisterSignatureProperty ( expression . ExtractPropertyInfo ( ) . Name ) ;
216188 }
217189
218190 public virtual bool Equals ( T other )
0 commit comments