Skip to content

Commit a541e92

Browse files
(GH-656) Add a new FastActivator to use throughout the entire solution
1 parent 9e76007 commit a541e92

File tree

12 files changed

+236
-43
lines changed

12 files changed

+236
-43
lines changed

src/DotNetToolkit.Repository.EntityFramework/Internal/EfRepositoryContextFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public IRepositoryContext Create()
6969
}
7070

7171
var underlyingContext = args.Count > 0
72-
? (TDbContext)Activator.CreateInstance(typeof(TDbContext), args.ToArray())
72+
? (TDbContext)FastActivator.CreateInstance(typeof(TDbContext), args.ToArray())
7373
: RepositoryDependencyResolver.Current.Resolve<TDbContext>();
7474

7575
return new EfRepositoryContext(underlyingContext);

src/DotNetToolkit.Repository.EntityFrameworkCore/Internal/EfCoreRepositoryContextFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public EfCoreRepositoryContextFactory(DbContextOptions contextOptions)
4545
public IRepositoryContext Create()
4646
{
4747
var underlyingContext = _contextOptions != null
48-
? (TDbContext)Activator.CreateInstance(typeof(TDbContext), _contextOptions)
48+
? (TDbContext)FastActivator.CreateInstance(typeof(TDbContext), _contextOptions)
4949
: RepositoryDependencyResolver.Current.Resolve<TDbContext>();
5050

5151
return new EfCoreRepositoryContext(underlyingContext);

src/DotNetToolkit.Repository.InMemory/Internal/FastActivator.cs

Lines changed: 0 additions & 32 deletions
This file was deleted.

src/DotNetToolkit.Repository/Extensions/Internal/TypeExtensions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public static Type GetGenericTypeOrDefault([NotNull] this Type type)
3131
/// <returns>The default value of the specified type.</returns>
3232
public static object GetDefault([NotNull] this Type type)
3333
{
34-
return type == null ? null : (type.GetTypeInfo().IsValueType ? Activator.CreateInstance(type) : null);
34+
return type == null ? null : (type.GetTypeInfo().IsValueType ? FastActivator.CreateInstance(type) : null);
3535
}
3636

3737
/// <summary>
@@ -176,7 +176,7 @@ public static object InvokeConstructor([NotNull] this Type type, [CanBeNull] Dic
176176
return null;
177177

178178
if (keyValues == null || keyValues.Count == 0)
179-
return Activator.CreateInstance(type);
179+
return FastActivator.CreateInstance(type);
180180

181181
var kvs = keyValues.ToDictionary(x => x.Key, x => x.Value);
182182
var ctors = type.GetConstructors();
@@ -245,7 +245,7 @@ select pi
245245
}
246246
else
247247
{
248-
obj = Activator.CreateInstance(type);
248+
obj = FastActivator.CreateInstance(type);
249249
}
250250

251251
if (kvs.Any())

src/DotNetToolkit.Repository/RepositoryDependencyResolver.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public object Resolve([NotNull] Type type)
108108
{
109109
try
110110
{
111-
result = Activator.CreateInstance(type);
111+
result = FastActivator.CreateInstance(type);
112112
}
113113
catch (Exception ex)
114114
{

src/DotNetToolkit.Repository/RepositoryFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public IRepository<TEntity, TKey1, TKey2, TKey3> Create<TEntity, TKey1, TKey2, T
100100
/// <returns>The new repository.</returns>
101101
public T CreateInstance<T>() where T : class
102102
{
103-
return (T)Activator.CreateInstance(typeof(T), new object[] { _options });
103+
return (T)FastActivator.CreateInstance(typeof(T), new object[] { _options });
104104
}
105105

106106
#endregion

src/DotNetToolkit.Repository/Services/ServiceFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public IService<TEntity, TKey1, TKey2, TKey3> Create<TEntity, TKey1, TKey2, TKey
8585
/// <returns>The new service.</returns>
8686
public T CreateInstance<T>() where T : class
8787
{
88-
return (T)Activator.CreateInstance(typeof(T), new object[] { _uowFactory });
88+
return (T)FastActivator.CreateInstance(typeof(T), new object[] { _uowFactory });
8989
}
9090

9191
#endregion

src/DotNetToolkit.Repository/Transactions/UnitOfWork.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public T CreateInstance<T>() where T : class
157157
{
158158
ThrowIfDisposed();
159159

160-
return (T)Activator.CreateInstance(typeof(T), new object[] { _options });
160+
return (T)FastActivator.CreateInstance(typeof(T), new object[] { _options });
161161
}
162162

163163
/// <summary>

src/DotNetToolkit.Repository/Transactions/UnitOfWorkFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public IUnitOfWork Create()
6363
/// <returns>The new repository.</returns>
6464
public T CreateInstance<T>() where T : class
6565
{
66-
return (T)Activator.CreateInstance(typeof(T), new object[] { _options });
66+
return (T)FastActivator.CreateInstance(typeof(T), new object[] { _options });
6767
}
6868

6969
#endregion
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
namespace DotNetToolkit.Repository.Utility
2+
{
3+
using System;
4+
using System.Collections.Concurrent;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Linq.Expressions;
8+
using System.Reflection;
9+
10+
internal static class FastActivator
11+
{
12+
#region Fields
13+
14+
private readonly static ConcurrentDictionary<Tuple<Type, Type[]>, ObjectActivator> _cache =
15+
new ConcurrentDictionary<Tuple<Type, Type[]>, ObjectActivator>(
16+
new TupleComparer());
17+
18+
#endregion
19+
20+
#region Delegates
21+
22+
private delegate object ObjectActivator(params object[] args);
23+
24+
#endregion
25+
26+
#region Private Methods
27+
28+
private static ObjectActivator GetActivator(ConstructorInfo ctor)
29+
{
30+
return (ObjectActivator)GetActivatorDelegate(typeof(ObjectActivator), ctor);
31+
}
32+
33+
private static Delegate GetActivatorDelegate(Type activatorDelegateType, ConstructorInfo ctor)
34+
{
35+
var paramsInfo = ctor.GetParameters();
36+
37+
var param = Expression.Parameter(typeof(object[]), "args");
38+
39+
var argsExp = new Expression[paramsInfo.Length];
40+
41+
for (int i = 0; i < paramsInfo.Length; i++)
42+
{
43+
Expression index = Expression.Constant(i);
44+
var paramType = paramsInfo[i].ParameterType;
45+
46+
Expression paramAccessorExp = Expression.ArrayIndex(param, index);
47+
48+
Expression paramCastExp = Expression.Convert(paramAccessorExp, paramType);
49+
50+
argsExp[i] = paramCastExp;
51+
}
52+
53+
var newExp = Expression.New(ctor, argsExp);
54+
55+
var lambda = Expression.Lambda(activatorDelegateType, newExp, param);
56+
57+
return lambda.Compile();
58+
}
59+
60+
private static ConstructorInfo GetMatchingConstructor(Type type, object[] args, out Type[] types)
61+
{
62+
types = (
63+
from arg in args
64+
where arg != null
65+
select arg.GetType()
66+
).ToArray();
67+
68+
return type.GetConstructor(types);
69+
}
70+
71+
#endregion
72+
73+
#region Public Methods
74+
75+
public static object CreateInstance(Type type, params object[] args)
76+
{
77+
if (type.GetTypeInfo().IsValueType)
78+
{
79+
return Activator.CreateInstance(type, args);
80+
}
81+
82+
var ctor = GetMatchingConstructor(type, args, out var argTypes);
83+
if (ctor == null)
84+
{
85+
if (args == null || args.Length == 0)
86+
{
87+
throw new InvalidOperationException(
88+
string.Format("No default constructor exists for class {0}", type.FullName));
89+
}
90+
91+
throw new InvalidOperationException(
92+
string.Format("No matching constructor found for class {0}", type.FullName));
93+
}
94+
95+
var key = Tuple.Create(type, argTypes);
96+
if (!_cache.TryGetValue(key, out var activator))
97+
{
98+
activator = GetActivator(ctor);
99+
100+
_cache[key] = activator;
101+
}
102+
103+
return activator(args);
104+
}
105+
106+
public static T CreateInstance<T>(params object[] args)
107+
{
108+
return (T)CreateInstance(typeof(T), args);
109+
}
110+
111+
#endregion
112+
113+
#region Nested Type: TupleComparer
114+
115+
class TupleComparer : IEqualityComparer<Tuple<Type, Type[]>>
116+
{
117+
public bool Equals(object[] x, object[] y)
118+
{
119+
return x.Length == y.Length && Enumerable.SequenceEqual(x, y);
120+
}
121+
122+
public bool Equals(Tuple<Type, Type[]> x, Tuple<Type, Type[]> y)
123+
{
124+
return x.Item1 == y.Item1 && Enumerable.SequenceEqual(x.Item2, y.Item2);
125+
}
126+
127+
public int GetHashCode(object[] o)
128+
{
129+
var result = o.Aggregate((a, b) => a.GetHashCode() ^ b.GetHashCode());
130+
return result != null ? result.GetHashCode() : 0;
131+
}
132+
133+
public int GetHashCode(Tuple<Type, Type[]> o)
134+
{
135+
unchecked
136+
{
137+
int hash = 17;
138+
139+
hash = hash * 23 + o.Item1.GetHashCode();
140+
141+
foreach (var item in o.Item2)
142+
{
143+
hash = hash * 23 + ((item != null) ? item.GetHashCode() : 0);
144+
}
145+
146+
return hash;
147+
}
148+
}
149+
}
150+
151+
#endregion
152+
}
153+
}

0 commit comments

Comments
 (0)