3

我的问题是这样的:

如果我要构建一个DynamicMethod对象,对应一个ConstructorInfo.Invoke调用,当我可以保证正确的类型时,我需要实现什么类型的 IL 以处理所有(或大多数)类型的参数在我拨打电话之前要传入多少个参数?


背景

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

我注意到的一件事是,当解析为具体类型时,最终我会使用ConstructorInfo.Invoke调用构造函数,并传入我已经计算出的参数数组。

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

例如,由于我拥有的构造函数匹配代码,要为我传入的预定义参数名称、类型和值找到匹配的构造函数,这个特定的调用调用不可能最终得到它应该能够的东西以正确的顺序、正确的类型和适当的值来处理,例如正确数量的参数。

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

  • ConstructorInfo.Invoke:1973 毫秒
  • 动态方法:93ms

这约占此分析应用程序总运行时间的 20%。换句话说,通过将 ConstructorInfo.Invoke 调用替换为具有相同功能的 DynamicMethod,我能够在处理基本的工厂范围服务时减少 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

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

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

4

2 回答 2

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 字符串
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: 回复
于 2009-12-29T16:41:07.920 回答
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" } );

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

于 2010-03-22T03:57:10.303 回答