2010-12-13 69 views
1

J'ai lu que je devrais créer et réutiliser des délégués pour obtenir la valeur d'une propriété d'un objet.Delegate.DynamicInvoke trop lent, comment changer l'appel à Invoke?

J'utilise ce code pour créer le délégué

var objParm = Expression.Parameter(property.DeclaringType, "o"); 

    Type delegateType = typeof(Func<,>).MakeGenericType(property.DeclaringType, property.PropertyType); 

    var lambda = Expression.Lambda(delegateType, Expression.Property(objParm, property.Name), objParm); 

    return lambda.Compile() 

Maintenant, je trouve que la façon d'utiliser le délégué dans l'appel de « DynamicInvoke ».

Maintenant, je veux changer l'appel à "invoquer" cause des raisons de performance.

J'ai essayé

Delegate.Method.Invoke(invokedObject, null); 

Mais après l'appel i obtenir l'exception

MethodInfo must be a RuntimeMethodInfo. 

J'ai une classe de cache pour chaque propriété où je peux stocker le délégué créé dynamiquement.

Que dois-je faire, je suis capable d'utiliser des appels "normaux"?

Merci beaucoup.

+1

«J'ai lu que je devrais créer et réutiliser les délégués pour obtenir la valeur d'une propriété d'un objet. » Dans de très rares cas c'est correct, "très" étant le mot clé ici. La plupart du temps, vous devriez juste vous «x.Property». – jason

+0

Oui, vous avez tout à fait raison, était mon erreur dans l'explication. A signifié en cohérence avec la réflexion (GetValue, SetValue). – Khh

+0

Le problème ici est que non seulement le nom de la propriété varie au moment de l'exécution, mais aussi le type. Cela vous oblige à utiliser une invocation basée sur la réflexion lente au lieu d'un appel de délégué de type sécurisé rapide. –

Répondre

-1

J'ai créé une classe que j'utilise lorsque j'ai besoin d'accéder à des propriétés en utilisant leur nom comme texte. La classe met en cache toutes les propriétés d'une classe.

Utilisation:

PropertyWrapper<User> wrapper = new PropertyWrapper<User>(); 
wrapper.SetValue("FirstName", "arne"); 
int age = (int)wrapper.GetValue("Age"); 

La classe

public class PropertyWrapper<T> 
{ 
    private Dictionary<string, Methods> _properties = new Dictionary<string, Methods>(); 
    private class Methods 
    { 
     public MethodBase Get { get; set; } 
     public MethodBase Set { get; set; } 
    } 

    public PropertyWrapper() 
    { 
     foreach (var item in typeof(T).GetProperties()) 
     { 
      if (!item.CanRead && !item.CanWrite) 
       continue; 

      var mappings = new Methods(); 
      if (item.CanRead) 
       mappings.Get = item.GetGetMethod(); 
      if (item.CanWrite) 
       mappings.Set = item.GetSetMethod(); 

      _properties.Add(item.Name, mappings); 
     } 
    } 

    public object GetValue(T instance, string name) 
    { 
     Methods mappings; 
     if (_properties.TryGetValue(name, out mappings) && mappings.Get != null) 
      return mappings.Get.Invoke(instance, null); 

     throw new MappingException("Specified property cannot be read", typeof(T), name); 
    } 

    public void SetValue(T instance, string name, object value) 
    { 
     Methods mappings; 
     if (_properties.TryGetValue(name, out mappings) && mappings.Set != null) 
     { 
      mappings.Set.Invoke(instance, new[] { value }); 
      return; 
     } 

     throw new MappingException("Specified property cannot be written.", typeof(T), name); 
    } 
} 

public class MappingException : Exception 
{ 
    public MappingException(string errMsg, Type type, string propertyName) 
     : base(errMsg) 
    { 
     ReflectedType = type; 
     PropertyName = propertyName; 
    } 

    public Type ReflectedType { get; private set; } 
    public string PropertyName { get; private set; } 
} 
+0

Ceci est encore lent. Pour obtenir des performances élevées, vous devez configurer 'mappings.Set (instance, value)' (c'est-à-dire, aucun tableau de paramètres non typé). –

6

Vous devez émettre un délégué Func<object,object> à la place, et le cas échéant lancer à l'intérieur du lambda et lors de la récupération du résultat. Si vous ne connaissez pas le type du délégué au moment de la compilation, vous ne pouvez pas l'appeler directement, car vous ne savez pas quel type d'arguments il prend, ni quel sera le type de retour.

Notez également que vous pourriez simplement créer un délégué autour de property.GetGetMethod() - il n'y a aucune raison de compiler votre propre méthode ici. Utilisez simplement la méthode getter de la propriété.

+0

merci pour l'indice, marquez la réponse de jgauffin cause du code sympa;) – Khh