DynamicMethod for ConstructorInfo.Invoke,我需要考虑什么?

时间:2009-12-29 14:27:22

标签: c# invoke il dynamicmethod

我的问题是:

  

如果我要构建一个DynamicMethod对象,对应于ConstructorInfo.Invoke调用,我需要实现哪些类型的IL才能处理所有(或大多数)类型的参数,当我可以保证在我打电话之前传递正确类型和数量的参数?


背景

我正在进行IoC容器的第3次迭代,目前正在进行一些分析,以确定是否有任何可以轻松减少大量时间使用的区域。

我注意到的一件事是,在解析为具体类型时,我最终会使用ConstructorInfo.Invoke调用构造函数,并传入一系列我已经解决过的参数。

我注意到,invoke方法有相当多的开销,我想知道大部分是否只是我所做的相同检查的不同实现。

例如,由于我拥有的构造函数匹配代码,为了找到我传入的预定义参数名称,类型和值的匹配构造函数,这个特定的调用调用不会以某种方式结束它应该能够以正确的顺序,正确的类型和适当的值来处理正确数量的参数。

在进行包含对我的resolve方法的一百万次调用的分析会话,然后将其替换为模仿Invoke调用的DynamicMethod实现时,分析时序如下:

  • ConstructorInfo.Invoke:1973ms
  • DynamicMethod:93ms

这占此分析应用程序总运行时的大约20%。换句话说,通过使用同样的DynamicMethod替换ConstructorInfo.Invoke调用,我可以在处理基本的工厂作用域服务时削减20%的运行时间(即所有解析调用最终都是构造函数调用)。

我认为这是相当可观的,并且需要仔细研究在这种情况下为构造函数构建稳定的DynamicMethod生成器需要做多少工作。

因此,动态方法将接受一个对象数组,并返回构造的对象,并且我已经知道了有问题的ConstructorInfo对象。

因此,看起来动态方法将由以下IL组成:

l001:    ldarg.0      ; the object array containing the arguments
l002:    ldc.i4.0     ; the index of the first argument
l003:    ldelem.ref   ; get the value of the first argument
l004:    castclass T  ; cast to the right type of argument (only if not "Object")
(repeat l001-l004 for all parameters, l004 only for non-Object types,
 varying l002 constant from 0 and up for each index)
l005:    newobj ci    ; call the constructor
l006:    ret

还有什么我需要考虑的吗?

请注意,我知道在“缩减访问模式”下运行应用程序时可能无法创建动态方法(有时大脑不会放弃这些条款),但在这种情况下我可以轻松检测到并且只是像以前一样调用原始构造函数,只需要开销和所有。

2 个答案:

答案 0 :(得分:1)

对于值类型,步骤l004应为l004: unbox.any T

找出你需要生成的正​​确IL的最简单方法是使用一些测试代码查看C#编译器生成的内容。

static void Test(object[] args)
{
  TestTarget((string)args[0], (int)args[1], (DateTime?)args[2]);
}

static void TestTarget(string s, int i, DateTime? dt){}

汇编为:

L_0000: ldarg.0 
L_0001: ldc.i4.0 
L_0002: ldelem.ref 
L_0003: castclass string
L_0008: ldarg.0 
L_0009: ldc.i4.1 
L_000a: ldelem.ref 
L_000b: unbox.any int32
L_0010: ldarg.0 
L_0011: ldc.i4.2 
L_0012: ldelem.ref 
L_0013: unbox.any [mscorlib]System.Nullable`1<valuetype [mscorlib]System.DateTime>
L_0018: call void Program::TestTarget(string, int32, valuetype [mscorlib]System.Nullable`1<valuetype [mscorlib]System.DateTime>)
L_001d: ret 

答案 1 :(得分:0)

有些库可以让它更容易(也更快)地使用反射。例如,Fasterflect可以生成用于调用任何构造函数的IL - 您需要做的就是将要在构造函数上使用的参数传递给它。

// note: class must have constructor with (int,string,string) signature
object obj = someType.CreateInstance( new { id=1, name="jens", foo="bar" } );

如果你没有一组与构造函数完全匹配的参数,那么库也能够探测适当的构造函数来调用。

// try to map id, name and foo to constructor parameters
// allows changing the order and permit fallback to setting fields/properties
// e.g. might result in call to ctor(string,string) and set field "id"
object obj = someType.TryCreateInstance( new { id=1, name="jens", foo="bar" } );

免责声明:我作为贡献者参与了该项目。