Ответ 1
Реализация RuntimePropertyInfo
(который является конкретным подклассом PropertyInfo
для типов времени выполнения) реализует GetValue
и SetValue
путем вызова методов getter и setter посредством отражения (MethodInfo.Invoke
), тогда как ваш сгенерированный делегат вероятно, вызывает методы напрямую. Поэтому вопрос сводится к: почему RuntimeMethodInfo.Invoke
настолько медленный по сравнению с скомпилированным вызовом?
Когда вы декомпилируете (или смотрите исходные источники для) RuntimeMethodInfo.Invoke
, вы можете видеть, что это, вероятно, потому, что Invoke
выполняет множество задач:
- он выполняет проверки согласованности (передают ли количество и типы передаваемых параметров подписи? прошел ли экземпляр, соответствующий типу объявления?), был ли экземпляр передан, хотя метод является статическим?),
- он выполняет видимость и (если проверка видимости обходится) проверки безопасности,
- он разворачивает массив параметров, обрабатывая параметры ref особым образом, чтобы их можно было записать позже,
- при необходимости он отключает параметры,
- ему нужно найти указатель метода на основе дескриптора типа времени выполнения и дескриптора метода, связанного с RuntimeMethodHandle, а затем вызвать метод
- при необходимости он возвращает возвращаемое значение и
- он помещает и помещает в массив параметров любые параметры ref/out.
Среда выполнения будет выполнять аналогичные проверки согласованности, безопасности и видимости при компиляции вашего делегата в исполняемый собственный код. Он также испускает код для бокса/распаковки и т.д. Однако он должен только один раз выполнять эти действия и затем может гарантировать, что код будет безопасным для выполнения. Это приводит к тому, что фактический метод вызывает очень дешевую операцию (загружайте параметры и переходите к адресу метода).
Напротив, каждый вызов RuntimeMethodInfo.Invoke
(и, следовательно, GetValue
/SetValue
) должен повторять всю работу, поскольку контекст - параметры, экземпляр и использование возвращаемого типа - неизвестен. Вероятно, поэтому это так медленно.
О том, что вам может не хватать: если вы испускаете своих собственных делегатов вызова свойств, вам, конечно же, нужно иметь дело с бокс/распаковкой, параметрами ref/out и т.д. самостоятельно.