Skip to content

Commit bde240e

Browse files
committed
(Perf) more refactoring
1 parent dd0162d commit bde240e

10 files changed

Lines changed: 296 additions & 218 deletions

File tree

src/Libraries/SmartStore.Core/Extensions/MiscExtensions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ namespace SmartStore
1111
{
1212
public static class MiscExtensions
1313
{
14-
public static void Dump(this Exception exc)
14+
public static void Dump(this Exception exception)
1515
{
1616
try
1717
{
18-
exc.StackTrace.Dump();
19-
exc.Message.Dump();
18+
exception.StackTrace.Dump();
19+
exception.Message.Dump();
2020
}
2121
catch { }
2222
}

src/Libraries/SmartStore.Core/Infrastructure/ComparableObject.cs

Lines changed: 45 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
using System.Linq.Expressions;
55
using System.Reflection;
66
using System.ComponentModel;
7+
using SmartStore.Utilities.Reflection;
8+
using SmartStore.Utilities;
9+
using System.Collections.Concurrent;
710

811
namespace 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)

src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public object ResolveUnregistered(Type type, ILifetimeScope scope = null)
7070

7171
if (!_cachedActivators.TryGetValue(type, out activator))
7272
{
73-
var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.CreateInstance | BindingFlags.Instance);
73+
var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
7474
foreach (var constructor in constructors)
7575
{
7676
var parameterTypes = constructor.GetParameters().Select(p => p.ParameterType).ToArray();

src/Libraries/SmartStore.Core/SmartStore.Core.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,7 @@
558558
<Compile Include="Utilities\DictionaryConverter.cs" />
559559
<Compile Include="Utilities\FileDownloadManager.cs" />
560560
<Compile Include="Utilities\FileSystemHelper.cs" />
561+
<Compile Include="Utilities\HashCodeCombiner.cs" />
561562
<Compile Include="Utilities\Inflector.cs" />
562563
<Compile Include="Utilities\Prettifier.cs" />
563564
<Compile Include="Utilities\Range.cs" />
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Runtime.CompilerServices;
6+
using System.Threading.Tasks;
7+
8+
/*
9+
Copied over from Microsoft.Framework.Internal
10+
*/
11+
12+
namespace SmartStore.Utilities
13+
{
14+
internal struct HashCodeCombiner
15+
{
16+
private long _combinedHash64;
17+
18+
public int CombinedHash
19+
{
20+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
21+
get { return _combinedHash64.GetHashCode(); }
22+
}
23+
24+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
25+
private HashCodeCombiner(long seed)
26+
{
27+
_combinedHash64 = seed;
28+
}
29+
30+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
31+
public HashCodeCombiner Add(IEnumerable e)
32+
{
33+
if (e == null)
34+
{
35+
Add(0);
36+
}
37+
else
38+
{
39+
var count = 0;
40+
foreach (object o in e)
41+
{
42+
Add(o);
43+
count++;
44+
}
45+
Add(count);
46+
}
47+
return this;
48+
}
49+
50+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
51+
public static implicit operator int (HashCodeCombiner self)
52+
{
53+
return self.CombinedHash;
54+
}
55+
56+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
57+
public HashCodeCombiner Add(int i)
58+
{
59+
_combinedHash64 = ((_combinedHash64 << 5) + _combinedHash64) ^ i;
60+
return this;
61+
}
62+
63+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
64+
public HashCodeCombiner Add(string s)
65+
{
66+
var hashCode = (s != null) ? s.GetHashCode() : 0;
67+
return Add(hashCode);
68+
}
69+
70+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
71+
public HashCodeCombiner Add(object o)
72+
{
73+
var hashCode = (o != null) ? o.GetHashCode() : 0;
74+
return Add(hashCode);
75+
}
76+
77+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
78+
public HashCodeCombiner Add<TValue>(TValue value, IEqualityComparer<TValue> comparer)
79+
{
80+
var hashCode = value != null ? comparer.GetHashCode(value) : 0;
81+
return Add(hashCode);
82+
}
83+
84+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
85+
public static HashCodeCombiner Start()
86+
{
87+
return new HashCodeCombiner(0x1505L);
88+
}
89+
}
90+
}

src/Libraries/SmartStore.Core/Utilities/Reflection/FastActivator.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public static T CreateInstance<T>(params object[] args)
131131
/// <returns>A reference to the newly created object.</returns>
132132
public static object CreateInstance(Type type, params object[] args)
133133
{
134-
Guard.ArgumentNotNull(() => type);
134+
Guard.ArgumentNotNull(type, "type");
135135

136136
if (args == null || args.Length == 0)
137137
{
@@ -164,16 +164,20 @@ private static FastActivator FindMatchingActivatorCore(FastActivator[] activator
164164
{
165165
return null;
166166
}
167-
168-
if (activators.Length == 1)
167+
168+
if (activators.Length == 1)
169169
{
170170
// this seems to be bad design, but it's on purpose for performance reasons.
171171
// In nearly ALL cases there is only one constructor.
172172
return activators[0];
173173
}
174174

175175
var argTypes = args.Select(x => x.GetType()).ToArray();
176-
var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.CreateInstance | BindingFlags.Public, null, argTypes, null);
176+
var constructor = type.GetConstructor(
177+
BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
178+
null,
179+
argTypes,
180+
null);
177181

178182
if (constructor != null)
179183
{

0 commit comments

Comments
 (0)