Un amico e io stavamo testando utilizzando espressioni compilate per la creazione dell'oggetto invece di Activator.CreateInstance<T>
e abbiamo ottenuto risultati interessanti. Abbiamo scoperto che quando eseguivamo lo stesso codice su ciascuna delle nostre macchine, abbiamo visto risultati completamente opposti. Ha ottenuto il risultato atteso, prestazioni significativamente migliori rispetto all'espressione compilata, mentre sono rimasto sorpreso nel vedere ileseguito da 2x.Activator.CreateInstance <T> vs Compiled Expression. Prestazioni inverse su due macchine diverse
Entrambi i computer correvano compilate in .NET 4,0
Computer 1 ha .NET 4.5 installato. Il computer 2 no.
Computer 1 oltre 100000 oggetti:
45ms - Type<Test>.New()
19ms - System.Activator.CreateInstance<Test>();
2 del calcolatore oltre 100000 oggetti:
13ms - Type<Test>.New()
86ms - System.Activator.CreateInstance<Test>();
Ed ecco il codice:
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; }
}
}
A proposito, [qui] (http://stackoverflow.com/a/969327/217219) è un modo migliore di usare 'Cronometro'. – kprobst
Non ho mai pensato di farlo, o –
Non una risposta, ma non hai bisogno di una cache di dizionari per tutto questo. C# statico lo fa per te. Vedi http://stackoverflow.com/a/16162475/661933 – nawfal