2015-01-19 6 views
2

У меня есть очень динамический код, который изначально использовал отражение с 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' 

Очевидно, что это не в состоянии справиться с автоматическим боксом и распаковкой типов значений. Есть ли способ сделать эту работу?

ответ

2

Позвоните Expression.Convert по результатам Expression.Call и преобразуйте его в object. Это приведет к операции по боксу в случае, если тип должен быть помещен в бокс.

+0

Да. Кажется, это работает. Благодарю. –

Смежные вопросы