У меня есть очень динамический код, который изначально использовал отражение с Type.GetProperty
и PropertyInfo.GetValue
для получения значений от объекта. Тогда я прочитал это о производительности GetValue
:Тип возвращаемого значения из скомпилированного выражения
https://lotsacode.wordpress.com/2010/04/12/getting-data-through-reflection-getvalue/
И решил попробовать и улучшить положение вещей путем создания и кэширования делегатов, как они делают в этой должности. Так что я создал что-то вроде этого:
private Delegate MakeAccessDelegate(PropertyInfo p)
{
var delType = typeof(Func<,>);
var genType = delType.MakeGenericType(p.DeclaringType, p.PropertyType);
var mi = p.GetAccessors().First();
return Delegate.CreateDelegate(genType, mi);
}
Но, потому что я не знаю, тип делегата, я вынужден использовать DynamicInvoke
, которая не является, на яркой стороне, не хуже, чем GetValue
, но похоже, тоже не лучше.
Так что я искал немного, и наткнулся на этот вопрос и ответ:
alternative for using slow DynamicInvoke on muticast delegate
Принятый ответ предлагает использовать скомпилированные делегата и это звучит как-то, что может помочь многим. Поскольку мои методы только добытчиками собственности, мне нужно, чтобы изменить его немного и пришел с этим (я ничего о деревья выражений не знаю, поэтому я лечу немного штору здесь):
delegate object CachedMethodDelegate(object instance);
private CachedMethodDelegate MakeAccessDelegate(PropertyInfo p)
{
var methodInfo = p.GetAccessors().First();
var instance = Expression.Parameter(typeof(object), "instance");
var lambda = Expression.Lambda<CachedMethodDelegate>(
Expression.Call(
Expression.Convert(instance, methodInfo.DeclaringType),
methodInfo
),
instance
);
return lambda.Compile();
}
И это похоже на работу. За исключением одной маленькой морщинки. Если свойство является типом значения (например, double
или datetime
), то он не может создать лямбда. Он бросает ArgumentException
на линии var lambda = ...
с ошибкой:
Expression of type 'System.Nullable`1[System.Double]' cannot be used
for return type 'System.Object'
Очевидно, что это не в состоянии справиться с автоматическим боксом и распаковкой типов значений. Есть ли способ сделать эту работу?
Да. Кажется, это работает. Благодарю. –