2013-07-02 9 views
8

Provare a creare due dizionari di delegati emessi per consentire prestazioni migliorate durante l'acquisizione/impostazione dinamica dei valori delle proprietà.Impossibile associare al metodo di destinazione durante la creazione di delegati per le proprietà

Codice:

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())); 

Tuttavia ottengo la seguente eccezione:

non può legarsi al metodo di destinazione perché la sua firma o la sicurezza trasparenza non è compatibile con quello del tipo delegato.

Da quello che ho letto questo sarà causato dalle proprietà/indicizzata/tipo valore statico, la raccolta Properties contiene immobili statiche o indicizzate ma però necessario far funzionare oggetti di tipo valore come int e double .

Come posso creare i getter/setter di cui ho bisogno mantenendo il mio codice astratto ed evitando i generici?

+0

Come si fa a creare 'Properties'? E quando ottieni esattamente questa eccezione? –

+0

Aggiunta la definizione della raccolta delle proprietà al codice incluso, ottengo l'eccezione quando il codice viene eseguito su un tipo. –

+0

Si potrebbe voler aggiungere questa riga di codice, dove si ottiene un'eccezione. aiuterà anche a capire come userete questi dizionari. –

risposta

7

Ok finito per trovare la mia risposta da questa domanda: MethodInfo.Invoke performance issue

In particolare questo articolo: Making reflection fly and exploring delegates

Ecco il jist del codice che ho finito con:

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)); 
    } 
} 

I delegati generati in media sembrano essere l'80% più veloci rispetto all'utilizzo del riflesso, quindi sono soddisfatto del risultato!

+1

Felice di aver trovato beneficio dall'articolo qui sopra! –

-1

Stavo ottenendo lo stesso errore. Ho usato l'API Expressions per risolvere questo problema.

Nota: Metodo a cui fa riferimento è

    non
  • generico.
  • è statico.

nome Delegato è la Formula e la sua firma è la seguente

public delegate float Formula(Dictionary<string, float> cr, 
           List<Dictionary<string, float>> allr); 
  1. Get MethodInfo che deve essere fatto riferimento come delegato

    Assembly assembly = results.CompiledAssembly; 
    var generatedType = assembly.GetType("First.NewClass"); 
    var generatedMethod = generatedType.GetMethod("FormulaMethod"); 
    
  2. Preparare argomenti del Delegato come parametro Espressione. Argomento 1: Dictionary<string, float> Argomento 2: List<Dictionary<string, float>>

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

    var = arg2Expression Expression.Parameter (typeof (Lista>));

  3. Generare il metodo finale Espressione di chiamata e restituire Delegato.

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