友人と私は、代わりにコンパイルされた式をオブジェクト作成に使用してテストしていましたがActivator.CreateInstance<T>
、いくつかの興味深い結果に出くわしました。各マシンで同じコードを実行すると、まったく逆の結果が得られることがわかりました。彼は期待どおりの結果を得て、コンパイルされた式から大幅に優れたパフォーマンスを達成しましたが、私はActivator.CreateInstance<T>
2 倍のパフォーマンスを見て驚きました。
両方のコンピューターが .NET 4.0 でコンパイルされて実行されました
コンピューター 1 には .NET 4.5 がインストールされています。コンピューター 2 にはありません。
100000 個を超えるオブジェクトのコンピューター 1:
45ms - Type<Test>.New()
19ms - System.Activator.CreateInstance<Test>();
コンピューター 2 100000 個を超えるオブジェクト:
13ms - Type<Test>.New()
86ms - System.Activator.CreateInstance<Test>();
コードは次のとおりです。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
namespace NewNew
{
class Program
{
static void Main(string[] args)
{
Stopwatch benchmark = Stopwatch.StartNew();
for (int i = 0; i < 100000; i++)
{
var result = Type<Test>.New();
}
benchmark.Stop();
Console.WriteLine(benchmark.ElapsedMilliseconds + " Type<Test>.New()");
benchmark = Stopwatch.StartNew();
for (int i = 0; i < 100000; i++)
{
System.Activator.CreateInstance<Test>();
}
benchmark.Stop();
Console.WriteLine(benchmark.ElapsedMilliseconds + " System.Activator.CreateInstance<Test>();");
Console.Read();
}
static T Create<T>(params object[] args)
{
var types = args.Select(p => p.GetType()).ToArray();
var ctor = typeof(T).GetConstructor(types);
var exnew = Expression.New(ctor);
var lambda = Expression.Lambda<T>(exnew);
var compiled = lambda.Compile();
return compiled;
}
}
public delegate object ObjectActivator(params object[] args);
public static class TypeExtensions
{
public static object New(this Type input, params object[] args)
{
if (TypeCache.Cache.ContainsKey(input))
return TypeCache.Cache[input](args);
var types = args.Select(p => p.GetType());
var constructor = input.GetConstructor(types.ToArray());
var paraminfo = constructor.GetParameters();
var paramex = Expression.Parameter(typeof(object[]), "args");
var argex = new Expression[paraminfo.Length];
for (int i = 0; i < paraminfo.Length; i++)
{
var index = Expression.Constant(i);
var paramType = paraminfo[i].ParameterType;
var accessor = Expression.ArrayIndex(paramex, index);
var cast = Expression.Convert(accessor, paramType);
argex[i] = cast;
}
var newex = Expression.New(constructor, argex);
var lambda = Expression.Lambda(typeof(ObjectActivator), newex, paramex);
var result = (ObjectActivator)lambda.Compile();
TypeCache.Cache.Add(input, result);
return result(args);
}
}
public class TypeCache
{
internal static IDictionary<Type, ObjectActivator> Cache;
static TypeCache()
{
Cache = new Dictionary<Type, ObjectActivator>();
}
}
public class Type<T>
{
public static T New(params object[] args)
{
return (T)typeof(T).New(args);
}
}
public class Test
{
public Test()
{
}
public Test(string name)
{
Name = name;
}
public string Name { get; set; }
}
}