gpt4 book ai didi

c# - 预编译的 lambda 表达式以创建具有带参数的构造函数的类

转载 作者:行者123 更新时间:2023-12-04 01:46:17 31 4
gpt4 key购买 nike

我目前正在使用 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 表达式完成类似的事情?

最佳答案

实际上,如果您只需要创建 一个 对象,使用 Expression.Compile更慢。但是,如果您缓存创建者函数,从长远来看它会更快,因为 lambda 性能会很好。

代码如下:

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 的新对象。


三种方式的小基准:

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);
}
}

在我的机器上产生以下结果( Release模式/在 Visual Studio 之外):

With Activator.CreateInstance: 3.0739 ticks per object
With Expression.Compile: 494.0388 ticks per object
With cached Expression.Compile: 0.1097 ticks per object

关于c# - 预编译的 lambda 表达式以创建具有带参数的构造函数的类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55137619/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com