2010-03-07 8 views
6

J'ai récemment commencé à expérimenter PostSharp et j'ai trouvé un aspect particulièrement utile pour automatiser l'implémentation de INotifyPropertyChanged. Vous pouvez voir l'exemple here. La fonctionnalité de base est excellente (toutes les propriétés seront notifiées), mais il y a des cas où je pourrais vouloir supprimer la notification. Par exemple, je pourrais savoir qu'une propriété particulière est définie une fois dans le constructeur et ne changera plus jamais. En tant que tel, il n'est pas nécessaire d'émettre le code pour NotifyPropertyChanged. Le surcoût est minime lorsque les classes ne sont pas fréquemment instanciées et je peux éviter le problème en passant d'une propriété générée automatiquement à une propriété sauvegardée sur le terrain et en écrivant dans le champ. Cependant, au moment d'apprendre ce nouvel outil, il serait utile de savoir s'il existe un moyen de marquer une propriété avec un attribut pour supprimer la génération de code. Je voudrais pouvoir faire quelque chose comme ceci:Suppression de la multidiffusion PostSharp avec l'attribut

[NotifyPropertyChanged] 
public class MyClass 
{ 
    public double SomeValue { get; set; } 

    public double ModifiedValue { get; private set; } 

    [SuppressNotify] 
    public double OnlySetOnce { get; private set; } 

    public MyClass() 
    { 
     OnlySetOnce = 1.0; 
    } 
} 

Répondre

5

Vous pouvez utiliser un MethodPointcut au lieu d'un MulticastPointcut, à savoir utiliser LINQ-over-réflexion et filtre contre PropertyInfo.IsDefined (votre attribut).

private IEnumerable<PropertyInfo> SelectProperties(Type type) 
    { 
     const BindingFlags bindingFlags = BindingFlags.Instance | 
      BindingFlags.DeclaredOnly 
              | BindingFlags.Public; 

     return from property 
        in type.GetProperties(bindingFlags) 
       where property.CanWrite && 
        !property.IsDefined(typeof(SuppressNotify)) 
       select property; 
    } 

    [OnLocationSetValueAdvice, MethodPointcut("SelectProperties")] 
    public void OnSetValue(LocationInterceptionArgs args) 
    { 
     if (args.Value != args.GetCurrentValue()) 
     { 
      args.ProceedSetValue(); 

      this.OnPropertyChangedMethod.Invoke(null); 
     } 
    } 
+0

Excellent, merci. C'est un outil très puissant et mon projet se sent nettement plus propre sans toute la fastidieuse plomberie INotifyPropertyChanged. –

0

Pour votre information, j'ai eu quelques problèmes avec l'exemple sur le site Sharpcrafters et a dû faire le changement suivant:

/// <summary> 
    /// Field bound at runtime to a delegate of the method <c>OnPropertyChanged</c>. 
    /// </summary> 
    [ImportMember("OnPropertyChanged", IsRequired = true, Order = ImportMemberOrder.AfterIntroductions)] 
    public Action<string> OnPropertyChangedMethod; 

Je pense qu'il introduisait le membre OnPropertyChanged, mais l'importation avant qu'il ait eu une chance d'être créé. Cela provoquerait l'échec de OnPropertySet car this.OnPropertyChangedMethod était null.

3

Une autre méthode simple, utilisez:

[NotifyPropertyChanged(AttributeExclude=true)] 

... pour supprimer les attributs d'une méthode particulière. Cela fonctionne même s'il y a un attribut global attaché à la classe (comme dans l'exemple ci-dessus).

Voici le code exemple complet:

[NotifyPropertyChanged] 
public class MyClass 
{ 
    public double SomeValue { get; set; } 

    public double ModifiedValue { get; private set; } 

    [NotifyPropertyChanged(AttributeExclude=True)] 
    public double OnlySetOnce { get; private set; } 

    public MyClass() 
    { 
     OnlySetOnce = 1.0; 
    } 
} 

Une fois que vous ajoutez cette ligne, PostSharp va même mettre à jour l'interface graphique MSVS pour supprimer le soulignement indiquant quels sont les attributs attachés à la méthode. Bien sûr, si vous exécutez le débogueur, il ignorera l'exécution des attributs de cette méthode particulière.