fork download
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Reflection;
  6. using System.Diagnostics;
  7.  
  8. public class ZeroParameters {
  9. public ZeroParameters() { }
  10. }
  11.  
  12. public class OneParameter {
  13. public OneParameter(int i) { }
  14. }
  15.  
  16. public class TwoParameters {
  17. public TwoParameters(int i, int j) { }
  18. }
  19.  
  20. public class ThreeParameters{
  21. public ThreeParameters(int i, int j, int k) { }
  22. }
  23.  
  24. public static class TypeExtensions
  25. {
  26. /// <summary>
  27. /// Returns an instance of the <paramref name="type"/> on which the method is invoked.
  28. /// </summary>
  29. /// <param name="type">The type on which the method was invoked.</param>
  30. /// <returns>An instance of the <paramref name="type"/>.</returns>
  31. public static object GetInstance(this Type type)
  32. {
  33. return GetInstance<TypeToIgnore>(type, null);
  34. }
  35.  
  36. /// <summary>
  37. /// Returns an instance of the <paramref name="type"/> on which the method is invoked.
  38. /// </summary>
  39. /// <typeparam name="TArg">The type of the argument to pass to the constructor.</typeparam>
  40. /// <param name="type">The type on which the method was invoked.</param>
  41. /// <param name="argument">The argument to pass to the constructor.</param>
  42. /// <returns>An instance of the given <paramref name="type"/>.</returns>
  43. public static object GetInstance<TArg>(this Type type, TArg argument)
  44. {
  45. return GetInstance<TArg, TypeToIgnore>(type, argument, null);
  46. }
  47.  
  48. /// <summary>
  49. /// Returns an instance of the <paramref name="type"/> on which the method is invoked.
  50. /// </summary>
  51. /// <typeparam name="TArg1">The type of the first argument to pass to the constructor.</typeparam>
  52. /// <typeparam name="TArg2">The type of the second argument to pass to the constructor.</typeparam>
  53. /// <param name="type">The type on which the method was invoked.</param>
  54. /// <param name="argument1">The first argument to pass to the constructor.</param>
  55. /// <param name="argument2">The second argument to pass to the constructor.</param>
  56. /// <returns>An instance of the given <paramref name="type"/>.</returns>
  57. public static object GetInstance<TArg1, TArg2>(this Type type, TArg1 argument1, TArg2 argument2)
  58. {
  59. return GetInstance<TArg1, TArg2, TypeToIgnore>(type, argument1, argument2, null);
  60. }
  61.  
  62. /// <summary>
  63. /// Returns an instance of the <paramref name="type"/> on which the method is invoked.
  64. /// </summary>
  65. /// <typeparam name="TArg1">The type of the first argument to pass to the constructor.</typeparam>
  66. /// <typeparam name="TArg2">The type of the second argument to pass to the constructor.</typeparam>
  67. /// <typeparam name="TArg3">The type of the third argument to pass to the constructor.</typeparam>
  68. /// <param name="type">The type on which the method was invoked.</param>
  69. /// <param name="argument1">The first argument to pass to the constructor.</param>
  70. /// <param name="argument2">The second argument to pass to the constructor.</param>
  71. /// <param name="argument3">The third argument to pass to the constructor.</param>
  72. /// <returns>An instance of the given <paramref name="type"/>.</returns>
  73. public static object GetInstance<TArg1, TArg2, TArg3>(
  74. this Type type,
  75. TArg1 argument1,
  76. TArg2 argument2,
  77. TArg3 argument3)
  78. {
  79. return InstanceCreationFactory<TArg1, TArg2, TArg3>
  80. .CreateInstanceOf(type, argument1, argument2, argument3);
  81. }
  82.  
  83. // To allow for overloads with differing numbers of arguments, we flag arguments which should be
  84. // ignored by using this Type:
  85. private class TypeToIgnore
  86. {
  87. }
  88.  
  89. private static class InstanceCreationFactory<TArg1, TArg2, TArg3>
  90. {
  91. // This dictionary will hold a cache of object-creation functions, keyed by the Type to create:
  92. private static readonly Dictionary<Type, Func<TArg1, TArg2, TArg3, object>> _instanceCreationMethods =
  93. new Dictionary<Type, Func<TArg1, TArg2, TArg3, object>>();
  94.  
  95. public static object CreateInstanceOf(Type type, TArg1 arg1, TArg2 arg2, TArg3 arg3)
  96. {
  97. CacheInstanceCreationMethodIfRequired(type);
  98.  
  99. return _instanceCreationMethods[type].Invoke(arg1, arg2, arg3);
  100. }
  101.  
  102. private static void CacheInstanceCreationMethodIfRequired(Type type)
  103. {
  104. // Bail out if we've already cached the instance creation method:
  105. if (_instanceCreationMethods.ContainsKey(type))
  106. {
  107. return;
  108. }
  109.  
  110. var sw = Stopwatch.StartNew();
  111. var argumentTypes = new[] { typeof(TArg1), typeof(TArg2), typeof(TArg3) };
  112.  
  113. // Get a collection of the constructor argument Types we've been given; ignore any
  114. // arguments which are of the 'ignore this' Type:
  115. Type[] constructorArgumentTypes = argumentTypes.Where(t => t != typeof(TypeToIgnore)).ToArray();
  116.  
  117. // Get the Constructor which matches the given argument Types:
  118. var constructor = type.GetConstructor(
  119. BindingFlags.Instance | BindingFlags.Public,
  120. null,
  121. CallingConventions.HasThis,
  122. constructorArgumentTypes,
  123. new ParameterModifier[0]);
  124.  
  125. // Get a set of Expressions representing the parameters which will be passed to the Func:
  126. var lamdaParameterExpressions = new[]
  127. {
  128. Expression.Parameter(typeof(TArg1), "param1"),
  129. Expression.Parameter(typeof(TArg2), "param2"),
  130. Expression.Parameter(typeof(TArg3), "param3")
  131. };
  132.  
  133. // Get a set of Expressions representing the parameters which will be passed to the constructor:
  134. var constructorParameterExpressions = lamdaParameterExpressions
  135. .Take(constructorArgumentTypes.Length)
  136. .ToArray();
  137.  
  138. // Get an Expression representing the constructor call, passing in the constructor parameters:
  139. var constructorCallExpression = Expression.New(constructor, constructorParameterExpressions);
  140.  
  141. // Compile the Expression into a Func which takes three arguments and returns the constructed object:
  142. var constructorCallingLambda = Expression
  143. .Lambda<Func<TArg1, TArg2, TArg3, object>>(constructorCallExpression, lamdaParameterExpressions)
  144. .Compile();
  145.  
  146. _instanceCreationMethods[type] = constructorCallingLambda;
  147. sw.Stop();
  148. Console.WriteLine("Lambda generator written in {0}", sw.Elapsed);
  149. Test._lambdaTimer = sw.Elapsed.TotalMilliseconds;
  150. }
  151. }
  152. }
  153.  
  154. public class Test {
  155.  
  156. public static double _lambdaTimer;
  157. public static void Main()
  158. {
  159. TestZero();
  160. GC.Collect();
  161. TestOne();
  162. GC.Collect();
  163. TestTwo();
  164. GC.Collect();
  165. TestThree();
  166. GC.Collect();
  167. }
  168.  
  169. public static void TestZero() {
  170. var average = 0.0;
  171. for (var i = 0; i < 100000; ++i) {
  172. var sw = Stopwatch.StartNew();
  173. new ZeroParameters();
  174. sw.Stop();
  175. average += sw.Elapsed.TotalMilliseconds;
  176. }
  177.  
  178. Console.WriteLine("new ZeroParameters(): {0}", average / 100000);
  179.  
  180. average = 0.0;
  181. for (var i = 0; i < 100000; ++i) {
  182. var sw = Stopwatch.StartNew();
  183. Activator.CreateInstance(typeof(ZeroParameters));
  184. sw.Stop();
  185. average += sw.Elapsed.TotalMilliseconds;
  186. }
  187.  
  188. Console.WriteLine("Activator.CreateInstance(typeof(ZeroParameters)): {0}", average / 100000);
  189.  
  190. average = 0.0;
  191. for (var i = 0; i < 100000; ++i) {
  192. var sw = Stopwatch.StartNew();
  193. typeof(ZeroParameters).GetInstance();
  194. sw.Stop();
  195. average += sw.Elapsed.TotalMilliseconds;
  196. }
  197.  
  198. Console.WriteLine("typeof(ZeroParameters).GetInstance(): {0} ({1} corrected)", average / 100000, (average - _lambdaTimer) / 100000);
  199. }
  200.  
  201. public static void TestOne() {
  202. var average = 0.0;
  203. for (var i = 0; i < 100000; ++i) {
  204. var sw = Stopwatch.StartNew();
  205. new OneParameter(0);
  206. sw.Stop();
  207. average += sw.Elapsed.TotalMilliseconds;
  208. }
  209.  
  210. Console.WriteLine("new OneParameter(0): {0}", average / 100000);
  211.  
  212. average = 0.0;
  213. for (var i = 0; i < 100000; ++i) {
  214. var sw = Stopwatch.StartNew();
  215. Activator.CreateInstance(typeof(OneParameter), 0);
  216. sw.Stop();
  217. average += sw.Elapsed.TotalMilliseconds;
  218. }
  219.  
  220. Console.WriteLine("Activator.CreateInstance(typeof(OneParameter), 0): {0}", average / 100000);
  221.  
  222. average = 0.0;
  223. for (var i = 0; i < 100000; ++i) {
  224. var sw = Stopwatch.StartNew();
  225. typeof(OneParameter).GetInstance(0);
  226. sw.Stop();
  227. average += sw.Elapsed.TotalMilliseconds;
  228. }
  229.  
  230. Console.WriteLine("typeof(OneParameter).GetInstance(0): {0} ({1} corrected)", average / 100000, (average - _lambdaTimer) / 100000);
  231. }
  232.  
  233. public static void TestTwo() {
  234. var average = 0.0;
  235. for (var i = 0; i < 100000; ++i) {
  236. var sw = Stopwatch.StartNew();
  237. new TwoParameters(0, 1);
  238. sw.Stop();
  239. average += sw.Elapsed.TotalMilliseconds;
  240. }
  241.  
  242. Console.WriteLine("new TwoParameters(0, 1): {0}", average / 100000);
  243.  
  244. average = 0.0;
  245. for (var i = 0; i < 100000; ++i) {
  246. var sw = Stopwatch.StartNew();
  247. Activator.CreateInstance(typeof(TwoParameters), 0, 1);
  248. sw.Stop();
  249. average += sw.Elapsed.TotalMilliseconds;
  250. }
  251.  
  252. Console.WriteLine("Activator.CreateInstance(typeof(TwoParameters), 0, 1): {0}", average / 100000);
  253.  
  254. average = 0.0;
  255. for (var i = 0; i < 100000; ++i) {
  256. var sw = Stopwatch.StartNew();
  257. typeof(TwoParameters).GetInstance(0, 1);
  258. sw.Stop();
  259. average += sw.Elapsed.TotalMilliseconds;
  260. }
  261.  
  262. Console.WriteLine("typeof(TwoParameters).GetInstance(0, 1): {0} ({1} corrected)", average / 100000, (average - _lambdaTimer) / 100000);
  263. }
  264.  
  265. public static void TestThree() {
  266. var average = 0.0;
  267. for (var i = 0; i < 100000; ++i) {
  268. var sw = Stopwatch.StartNew();
  269. new ThreeParameters(0, 1, 2);
  270. sw.Stop();
  271. average += sw.Elapsed.TotalMilliseconds;
  272. }
  273.  
  274. Console.WriteLine("new ThreeParameters(0, 1, 2): {0}", average / 100000);
  275.  
  276. average = 0.0;
  277. for (var i = 0; i < 100000; ++i) {
  278. var sw = Stopwatch.StartNew();
  279. Activator.CreateInstance(typeof(ThreeParameters), 0, 1, 2);
  280. sw.Stop();
  281. average += sw.Elapsed.TotalMilliseconds;
  282. }
  283.  
  284. Console.WriteLine("Activator.CreateInstance(typeof(ThreeParameters), 0, 1, 2): {0}", average / 100000);
  285.  
  286. average = 0.0;
  287. for (var i = 0; i < 100000; ++i) {
  288. var sw = Stopwatch.StartNew();
  289. typeof(ThreeParameters).GetInstance(0, 1, 2);
  290. sw.Stop();
  291. average += sw.Elapsed.TotalMilliseconds;
  292. }
  293.  
  294. Console.WriteLine("typeof(ThreeParameters).GetInstance(0, 1, 2): {0} ({1} corrected)", average / 100000, (average - _lambdaTimer) / 100000);
  295. }
  296. }
Success #stdin #stdout 0.99s 24884KB
stdin
Standard input is empty
stdout
new ZeroParameters(): 7.20339999999711E-05
Activator.CreateInstance(typeof(ZeroParameters)): 0.000601372000000224
Lambda generator written in 00:00:00.0312038
typeof(ZeroParameters).GetInstance(): 0.000522474000002971 (0.000210436000002971 corrected)
new OneParameter(0): 2.90370000000144E-05
Activator.CreateInstance(typeof(OneParameter), 0): 0.00230844999999696
Lambda generator written in 00:00:00.0032450
typeof(OneParameter).GetInstance(0): 0.000128744999999799 (9.62949999997987E-05 corrected)
new TwoParameters(0, 1): 2.58680000000103E-05
Activator.CreateInstance(typeof(TwoParameters), 0, 1): 0.00238636299999745
Lambda generator written in 00:00:00.0003177
typeof(TwoParameters).GetInstance(0, 1): 9.65609999999102E-05 (9.33839999999102E-05 corrected)
new ThreeParameters(0, 1, 2): 3.12910000000216E-05
Activator.CreateInstance(typeof(ThreeParameters), 0, 1, 2): 0.00253207399999785
Lambda generator written in 00:00:00.0019575
typeof(ThreeParameters).GetInstance(0, 1, 2): 0.000112223999999865 (9.26489999998645E-05 corrected)