2013-07-02 1 views
8

Попытка создания двух словарей испущенных делегатов для повышения производительности при динамическом получении/настройке значений свойств.Невозможно привязываться к целевому методу при создании делегатов для свойств

Код:

Properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance) 
        .Where(p => p.CanRead && !p.GetIndexParameters().Any()) 
        .AsEnumerable(); 
    PropertyGetters = Properties.ToDictionary(p => p.Name, p => (Func<object, object>)Delegate.CreateDelegate(typeof(Func<object, object>), p.GetGetMethod())); 
    PropertySetters = Properties.Where(p => p.GetSetMethod() != null) 
        .ToDictionary(p => p.Name, p => (Action<object, object>)Delegate.CreateDelegate(typeof(Action<object, object>), p.GetSetMethod())); 

Однако я получаю следующее исключение:

не может связываться с целевой метод, потому что его подпись или безопасность прозрачность не совместима с типом делегата.

Из того, что я прочитал это будет обусловлено свойствами статической/индексируются/тип значения, то Properties коллекция не содержит статические или индексированные свойства, но я, тем не менее это нужно, чтобы работать для свойств типа значения, такие как int и double ,

Как я могу создать геттеры/сеттеры, которые мне нужны, сохраняя мой код абстрактным и избегая дженериков?

+0

Как создать 'Properties'? И когда именно вы получаете это исключение? –

+0

Добавил определение коллекции свойств к включенному коду, я получаю исключение, когда код выполняется по типу. –

+0

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

ответ

7

Ok в конечном итоге найти свой ответ от этого вопроса: MethodInfo.Invoke performance issue

Более конкретно эта статья: Making reflection fly and exploring delegates

Вот тэк кода, который я закончил с:

public class Helper 
{ 
    private IDictionary<string, Func<object, object>> PropertyGetters { get; set; } 

    private IDictionary<string, Action<object, object>> PropertySetters { get; set; } 

    public static Func<object, object> CreateGetter(PropertyInfo property) 
    { 
     if (property == null) 
      throw new ArgumentNullException("property"); 

     var getter = property.GetGetMethod(); 
     if (getter == null) 
      throw new ArgumentException("The specified property does not have a public accessor."); 

     var genericMethod = typeof(Helper).GetMethod("CreateGetterGeneric"); 
     MethodInfo genericHelper = genericMethod.MakeGenericMethod(property.DeclaringType, property.PropertyType); 
     return (Func<object, object>)genericHelper.Invoke(null, new object[] { getter }); 
    } 

    public static Func<object, object> CreateGetterGeneric<T, R>(MethodInfo getter) where T : class 
    { 
     Func<T, R> getterTypedDelegate = (Func<T, R>)Delegate.CreateDelegate(typeof(Func<T, R>), getter); 
     Func<object, object> getterDelegate = (Func<object, object>)((object instance) => getterTypedDelegate((T)instance)); 
     return getterDelegate; 
    } 

    public static Action<object, object> CreateSetter(PropertyInfo property) 
    { 
     if (property == null) 
      throw new ArgumentNullException("property"); 

     var setter = property.GetSetMethod(); 
     if (setter == null) 
      throw new ArgumentException("The specified property does not have a public setter."); 

     var genericMethod = typeof(Helper).GetMethod("CreateSetterGeneric"); 
     MethodInfo genericHelper = genericMethod.MakeGenericMethod(property.DeclaringType, property.PropertyType); 
     return (Action<object, object>)genericHelper.Invoke(null, new object[] { setter }); 
    } 

    public static Action<object, object> CreateSetterGeneric<T, V>(MethodInfo setter) where T : class 
    { 
     Action<T, V> setterTypedDelegate = (Action<T, V>)Delegate.CreateDelegate(typeof(Action<T, V>), setter); 
     Action<object, object> setterDelegate = (Action<object, object>)((object instance, object value) => { setterTypedDelegate((T)instance, (V)value); }); 
     return setterDelegate; 
    } 

    public Helper(Type type) 
    { 
     var Properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance) 
        .Where(p => p.CanRead && !p.GetIndexParameters().Any()).AsEnumerable(); 
     PropertyGetters = Properties.ToDictionary(p => p.Name, p => CreateGetter(p)); 
     PropertySetters = Properties.Where(p => p.GetSetMethod() != null) 
      .ToDictionary(p => p.Name, p => CreateSetter(p)); 
    } 
} 

Сгенерированные делегаты в среднем кажутся на 80% быстрее, чем использование отражения, поэтому я доволен результатом!

+1

Рад, что вы нашли преимущество в статье выше! –

-1

У меня была такая же ошибка. Я использовал API выражений, чтобы исправить эту проблему.

Примечание: Метод ссылаться является

  • не родовым.
  • является статическим.

имя Делегат Формула и его подпись следующим

public delegate float Formula(Dictionary<string, float> cr, 
           List<Dictionary<string, float>> allr); 
  1. Получить MethodInfo, который должен ссылаться как делегат

    Assembly assembly = results.CompiledAssembly; 
    var generatedType = assembly.GetType("First.NewClass"); 
    var generatedMethod = generatedType.GetMethod("FormulaMethod"); 
    
  2. Приготовьте аргументы делегата в качестве параметра Expression. Аргумент 1: Dictionary<string, float> Аргумент 2: List<Dictionary<string, float>>

    var arg1Expression = Expression.Parameter(typeof(Dictionary<string, float>)); 
    

    вар arg2Expression = Expression.Parameter (TypeOf (Список>));

  3. Создать окончательный метод Вызвать выражение и вернуть делегат.

    var methodCall = Expression.Call(generatedMethod, 
               arg1Expression, 
               arg2Expression); 
    
    return Expression.Lambda <Formula> (methodCall, 
                arg1Expression, 
                arg2Expression).Compile(); 
    

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

  • Нет связанных вопросов^_^