é��常è€�的问题,但是有新的ç”案 😉
表达å¼�æ ‘ç‰ˆæœ¬ï¼šï¼ˆæˆ‘è®¤ä¸ºè¿™æ˜¯æœ€å¿«å’Œæœ€å¹²å‡€çš„è§£å†³æ–¹æ¡ˆï¼‰
åƒ�Welly Tambunanæ‰€è¯´çš„é‚£æ ·ï¼Œâ€œæˆ‘ä»¬ä¹Ÿå�¯ä»¥ä½¿ç”¨è¡¨è¾¾å¼�æ ‘æ�¥æ�„建对象â€�
这将为给定类å�‹/å�‚数生æˆ�一个'æ�„é€ å‡½æ•°'(函数)。它返å›�一个委托,并将å�‚æ•°ç±»å�‹ä½œä¸ºå¯¹è±¡æ•°ç»„æ�¥å�—。
以下是代ç �:
public delegate object ConstructorDelegate(params object[] args);
public static ConstructorDelegate CreateConstructor(Type type, params Type[] parameters)
{
var constructorInfo = type.GetConstructor(parameters);
var paramExpr = Expression.Parameter(typeof(Object[]));
var constructorParameters = parameters.Select((paramType, index) =>
Expression.Convert(
Expression.ArrayAccess(
paramExpr,
Expression.Constant(index)),
paramType)).ToArray();
var body = Expression.New(constructorInfo, constructorParameters);
var constructor = Expression.Lambda<ConstructorDelegate>(body, paramExpr);
return constructor.Compile();
}
示例 MyClass:
public class MyClass
{
public int TestInt { get; private set; }
public string TestString { get; private set; }
public MyClass(int testInt, string testString)
{
TestInt = testInt;
TestString = testString;
}
}
使用方法:
var myConstructor = CreateConstructor(typeof(MyClass), typeof(int), typeof(string));
var myObject = myConstructor(10, "test message");
另一个例子:将类型作为数组传递
var type = typeof(MyClass);
var args = new Type[] { typeof(int), typeof(string) };
var myConstructor = CreateConstructor(type, args);
var myObject = myConstructor(10, "test message");
表达式的DebugView
.Lambda
.New TestExpressionConstructor.MainWindow+MyClass(
(System.Int32)$var1[0],
(System.String)$var1[1])
}
这与生成的代码等效:
public object myConstructor(object[] var1)
{
return new MyClass(
(System.Int32)var1[0],
(System.String)var1[1]);
}
小缺陷
所有值类型参数在传递时都会被装箱为对象数组。
简单性能测试:
private void TestActivator()
{
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 1024 * 1024 * 10; i++)
{
var myObject = Activator.CreateInstance(typeof(MyClass), 10, "test message");
}
sw.Stop();
Trace.WriteLine("Activator: " + sw.Elapsed);
}
private void TestReflection()
{
var constructorInfo = typeof(MyClass).GetConstructor(new[] { typeof(int), typeof(string) });
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 1024 * 1024 * 10; i++)
{
var myObject = constructorInfo.Invoke(new object[] { 10, "test message" });
}
sw.Stop();
Trace.WriteLine("Reflection: " + sw.Elapsed);
}
private void TestExpression()
{
var myConstructor = CreateConstructor(typeof(MyClass), typeof(int), typeof(string));
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 1024 * 1024 * 10; i++)
{
var myObject = myConstructor(10, "test message");
}
sw.Stop();
Trace.WriteLine("Expression: " + sw.Elapsed);
}
TestActivator();
TestReflection();
TestExpression();
结果:
Activator: 00:00:13.8210732
Reflection: 00:00:05.2986945
Expression: 00:00:00.6681696
使用 表达式
的速度比调用 ConstructorInfo
快约 8倍,比使用 Activator
快约 20倍