DynamicMethod для constructorinfo.invoke, что мне нужно рассмотреть?

StackOverflow https://stackoverflow.com/questions/1974877

  •  21-09-2019
  •  | 
  •  

Вопрос

Мой вопрос:

Если я собираюсь построить Динамикметод объект, соответствующий Constructorinfo.invoke Звоните, какие типы IL мне нужно реализовать, чтобы справиться со всеми (или большинством) типами аргументов, когда я могу гарантировать, что правильный тип и количество аргументов будут переданы, прежде чем я сделаю звонок?


Фон

Я нахожусь на своей третьей итерации моего контейнера IOC, и в настоящее время делаю некоторое профилирование, чтобы выяснить, есть ли какие -либо области, где я могу легко сбрить большое количество времени.

Одна вещь, которую я заметил, заключается в том, что при разрешении на конкретный тип, в конечном итоге я в конечном итоге получаю конструктор, используя, используя Constructorinfo.invoke, передавая множество аргументов, которые я выпустил.

Что я заметил, так это то, что метод Invoke имеет немного накладных расходов, и мне интересно, является ли большая часть этого просто разные реализации тех же проверок, которые я делаю.

Например, из -за кода сопоставления конструктора, который у меня есть, чтобы найти соответствующий конструктор для предопределенных имен параметров, типов и значений, которые я передал, этот конкретный вызов не будет в конечном итоге, что он должен быть в состоянии справиться с правильным количеством аргументов, в правильном порядке, правильного типа и с соответствующими значениями.

При профилировании, содержащем миллион звонков в мой метод разрешения, а затем заменить его на Динамикметод Реализация, которая имитирует звонок вызвать, сроки профилирования были такими, как это:

  • Constructorinfo.invoke: 1973ms
  • DynamicMethod: 93 мс

Это составляет около 20% от общего времени выполнения этого приложения профилирования. Другими словами, заменив звонок 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

Есть ли что -нибудь еще, что мне нужно рассмотреть?

Обратите внимание, что я знаю, что создание динамических методов, вероятно, не будет доступно при запуске приложения в «режиме уменьшенного доступа» (иногда мозг просто не откажется от этих терминов), но в этом случае я могу легко обнаружить это и просто Называя оригинального конструктора, как и раньше, с накладными голосами и всем.

Это было полезно?

Решение

Для типов стоимости шаг 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 

Другие советы

Есть библиотеки, доступные, чтобы облегчить (и быстрее) работать с размышлением. Например, Быстрее может генерировать 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" } );

Отказ от ответственности: я участвую в указанном проекте в качестве участника.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top