我和一位朋友正在测试使用编译表达式来创建对象而不是Activator.CreateInstance<T>
,并遇到了一些有趣的结果。我们发现当我们在每台机器上运行相同的代码时,我们看到完全相反的结果。他得到了预期的结果,从编译的表达式中获得了明显更好的性能,而我惊讶地看到Activator.CreateInstance<T>
执行了2x。
两台计算机都是在.NET 4.0中编译的
计算机1安装了.NET 4.5。计算机2没有。
计算机1超过100000个对象:
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; }
}
}
答案 0 :(得分:8)
至少有两个原因:
Type<Test>.New()
或System.Activator.CreateInstance<Test>()
的开销相对较大。因此,我将100000改为10000000。通过这两个变化,这两种方法需要大约相同的时间。在我的系统中,对于这两种方法,我在1100到1200之间,有时一个更高,有时另一个是。
请注意Activator.CreateInstance<T>()
只能调用默认构造函数,而New()
接受许多参数。如果你使New()
功能不那么强大,并且总是使用默认构造函数,那么它比我系统上的Activator.CreateInstance<T>()
略快。
另请注意,如果应使用两个相同类型的不同构造函数,则根据传递的参数,对带有参数的构造函数的处理实际上不起作用。您可以选择一个构造函数用于整个程序的其余部分。