我当前正在使用Activator.CreateInstance
创建一个类的实例,该类的类型作为通用参数传入。问题是,这太慢了。我读过某个地方可以使用预编译的lambda表达式执行相同的操作,但是,由于需要将参数传递给所创建的类的实例,因此在我的情况下难以实现。
当前我正在执行以下操作
public class Class1
{
private int TestVariable;
public Class1(int testVariable)
{
TestVariable = testVariable;
}
public void TestMethod()
{
Console.WriteLine($"Test Variable was {TestVariable}");
}
}
public object Test<T>(params object[] parameters)
{
var instance = (T) Activator.CreateInstance(typeof(T), BindingFlags.Instance, null, new object[] {9999}, null);
var testMethod = typeof(T).GetMethod("TestMethod", BindingFlags.Instance);
return testMethod.Invoke(instance, parameters)
}
如何使用预编译的lambda表达式完成与此类似的操作?
答案 0 :(得分:0)
实际上,如果您只需要创建一个对象,则使用Object.values(obj).reduce((acc, { dataText, ...rest }) => ({ ...acc, [dataText]: rest }), {})
的速度会更快。但是,如果您缓存了creator函数,从长远来看它将更快,因为lambda性能会很好。
代码如下:
Expression.Compile
static Func<TArg, T> CreateCreator<TArg, T>()
{
var constructor = typeof(T).GetConstructor(new Type[] { typeof(TArg) });
var parameter = Expression.Parameter(typeof(TArg), "p");
var creatorExpression = Expression.Lambda<Func<TArg, T>>(
Expression.New(constructor, new Expression[] { parameter }), parameter);
return creatorExpression.Compile();
}
有了这个,您可以使用Func<TArg, T> creator = CreateCreator<TArg, T>();
创建creator(arg)
的新对象。
三种方式的小型基准测试:
T
在我的机器上(发布模式/ Visual Studio外部)产生以下结果:
class Program
{
static void Main(string[] args)
{
// warm up
Test1<Class1>(0);
Test2<int, Class1>(0);
const int numiter = 10000;
var sw1 = Stopwatch.StartNew();
for (int i = 0; i < numiter; i++)
Test1<Class1>(i);
sw1.Stop();
Console.WriteLine($"With Activator.CreateInstance: " +
$"{(double)sw1.ElapsedTicks / numiter} ticks per object");
var sw2 = Stopwatch.StartNew();
for (int i = 0; i < numiter; i++)
Test2<int, Class1>(i);
sw2.Stop();
Console.WriteLine($"With Expression.Compile: " +
$"{(double)sw2.ElapsedTicks / numiter} ticks per object");
var sw3 = Stopwatch.StartNew();
var creator = CreateCreator<int, Class1>();
for (int i = 0; i < numiter; i++)
creator(i);
sw3.Stop();
Console.WriteLine($"With cached Expression.Compile: " +
$"{(double)sw3.ElapsedTicks / numiter} ticks per object");
}
static public object Test1<T>(params object[] parameters)
{
var instance = (T)Activator.CreateInstance(
typeof(T), BindingFlags.Instance | BindingFlags.Public, null, parameters, null);
return instance;
}
static Func<TArg, T> CreateCreator<TArg, T>()
{
var constructor = typeof(T).GetConstructor(new Type[] { typeof(TArg) });
var parameter = Expression.Parameter(typeof(TArg), "p");
var creatorExpression = Expression.Lambda<Func<TArg, T>>(
Expression.New(constructor, new Expression[] { parameter }), parameter);
return creatorExpression.Compile();
}
static public object Test2<TArg, T>(TArg arg)
{
var creator = CreateCreator<TArg, T>();
return creator(arg);
}
}