La implementación de RuntimePropertyInfo
(que es la subclase concreta de PropertyInfo
de tipos en tiempo de ejecución) implementa GetValue
y SetValue
invocando los métodos get y set a través de la reflexión (MethodInfo.Invoke
), mientras que el delegado generada probablemente llamadas directamente los métodos. Por lo tanto, la pregunta se reduce a: ¿por qué es tan lento RuntimeMethodInfo.Invoke
en comparación con una invocación compilada?
Cuando descompilar (o mirar las fuentes de referencia para) RuntimeMethodInfo.Invoke
, se puede ver que esto es probablemente porque Invoke
lleva a cabo una gran cantidad de tareas:
- que realiza comprobaciones de coherencia (hacer el número y tipos de los parámetros aprobados coinciden con la firma? ¿la instancia aprobada coincide con el tipo de declaración? ¿se pasó una instancia aunque el método es estático?),
- realiza la visibilidad y (si se evitan los controles de visibilidad) las verificaciones de seguridad
- la matriz de parámetros, tratando a la referencia rámetros de una manera especial para que puedan ser escritas de nuevo a tarde,
- que unboxes parámetros si es necesario,
- que necesita para encontrar el puntero del método basado en el mango mango tipo de tiempo de ejecución y el método asociado con el RuntimeMethodHandle y luego invocar el método,
- pone el valor de retorno si es necesario, y
- inserta y coloca en el conjunto de parámetros los parámetros de ref/out.
El tiempo de ejecución realizará comprobaciones de coherencia, seguridad y visibilidad similares cuando compila su delegado en código nativo ejecutable. También emite código para boxeo/unboxing, etc. Sin embargo, solo necesita hacer estas cosas una vez, y puede garantizar que el código sea seguro de ejecutar. Esto hace que el método real llame a una operación muy económica (cargue los parámetros y salte a la dirección del método).
Por el contrario, cada llamada a RuntimeMethodInfo.Invoke
(y por tanto a GetValue
/SetValue
) tiene que repetir todo el trabajo, ya que el contexto - los parámetros, ejemplo, y el uso del tipo de retorno - no se conoce. Y esta es probablemente la razón por la cual es tan lento.
Acerca de lo que puede estar perdiendo: si usted emite sus propios delegados de invocación de propiedad, usted por supuesto necesita lidiar con boxeo/unboxing, ref/out parameters, etc. usted mismo.
FYI, si usted está buscando una manera más fácil de conseguir un aumento de rendimiento de Reflection.Emit, sólo podría Delegate.CreateDelegate con PropertyInfo.GetGetMethod/PropertyInfo.GetSetMethod (y almacenar en caché el delegado por supuesto). – Ani
Tendría que bloquear la instancia del objeto en el delegado. Los métodos 'GetValue' y' SetValue' toman la instancia del objeto, en el momento de la llamada. –
Delegate.CreateDelegate puede crear objetos delegados de instancia abierta y cerrada. – Ani