2012-03-28 6 views
0

Ich habe Schwierigkeiten, meine Frage in Form einer Google-Abfrage zusammenzufassen (vielleicht mein Foo ist aus):Hinzufügen von Funktionalität zu Schnittstellen/Klassen über C# -Attribute?

Ich versuche, eine Schnittstelle oder eine Klasse einige Funktionalität zu geben, indem Sie nicht die Typdefinition selbst bearbeiten , sondern indem man das Objekt mit einer Schnittstelle verkleidet. Das einfache Beispiel, das ich versuche, ist das Anfügen eines Attributs namens [Notify], für das ein Eigenschaftsänderungsereignis definiert ist, das im Idealfall die Verwendung des Ereignisses in der Schnittstelle/Klasse angibt. Ich habe ich die Öffnung nicht erfolgreich gewesen mit diesem so zu jedem Gerät möglich (falls vorhanden), um das Äquivalent zu erreichen:

[Notify] 
public interface IPerson 
{ 
    string Name { get; set; } 
} 

    [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false, Inherited = false)] 
    public class Notify: Attribute 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 

     protected void OnPropertyChanged(string name) 
     { 
      PropertyChangedEventHandler handler = PropertyChanged; 
      if (handler != null) 
      { 
       handler(this, new PropertyChangedEventArgs(name)); 
      } 
     } 

    } 

eine IPerson Verwendung:

IPerson person = PersonFactory.create(); 
person.PropertyChanged += SomeDelegateHere // the center peice 

Natürlich, wenn Sie diese kopiert Code, Person wird nicht PropertyChanged haben. Mit oder ohne Attribute, gibt es eine Möglichkeit, die IPerson mehr Funktionalität zu erreichen, ohne die Definition zu ändern (d. H. Keine Schnittstelle oder Basisklasse hinzufügen). Ich verstehe, dass sich auch die Attribute ändern, aber ich bin mit dem Ansatz der Metadaten zufrieden.

Vielen Dank im Voraus für jedes Licht, das vergossen werden kann.

Antwort

1

Sie suchen nach solchen Ereignissen wie Methodenaufrufen und fügen einige Aktionen an diese Ereignisse an. Dies ist kein Standardmerkmal von C#, aber es kann über ein solches AOP-Framework wie PostSharp erfolgen. PostSharp fügt diese Funktionalität hinzu, indem Code während der Erstellung geändert wird (Reflection wird nicht verwendet). Hier

ist, was Sie mit Postsharp implementieren müssen:

[Serializable] 
[IntroduceInterface(typeof(INotifyPropertyChanged), OverrideAction = InterfaceOverrideAction.Ignore)] 
[MulticastAttributeUsage(MulticastTargets.Class, Inheritance = MulticastInheritance.Strict)] 
public class NotifyAttribute : InstanceLevelAspect, INotifyPropertyChanged 
{   
    [ImportMember("OnPropertyChanged", IsRequired = false)] 
    public Action<string> OnPropertyChangedMethod;  

    [IntroduceMember(Visibility = Visibility.Family, IsVirtual = true, OverrideAction = MemberOverrideAction.Ignore)] 
    public void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null)    
      PropertyChanged(Instance, new PropertyChangedEventArgs(propertyName));    
    } 

    [IntroduceMember(OverrideAction = MemberOverrideAction.Ignore)] 
    public event PropertyChangedEventHandler PropertyChanged; 

    [OnLocationSetValueAdvice] 
    [MulticastPointcut(Targets = MulticastTargets.Property, Attributes = MulticastAttributes.Instance)] 
    public void OnPropertySet(LocationInterceptionArgs args) 
    {    
     if (args.Value == args.GetCurrentValue()) return; 

     args.ProceedSetValue(); 
     this.OnPropertyChangedMethod.Invoke(args.Location.Name);    
    } 
} 

Implementierungsdetails Sie here finden.

Die Nutzung ist sehr einfach:

[Notify] 
public class Person 
{ 
    public string Name { get; set; } 
} 

Beachten Sie, dass die tatsächlichen Code wird in die Montage während der Kompilierung injiziert werden. Attribute können keine Funktionalität hinzufügen. Sie sind nur Metadaten. In diesem Fall Metadaten, die von PostSharp verwendet werden, um Code zu generieren und in die Assembly zu injizieren.

1

Attribute im Allgemeinen nicht tun alles. Ihr Zweck ist mehr, Deskriptoren oder Meta Daten für die Typen/Felder/Eigenschaften/etc zu liefern, die sie verzieren.

Eine allgemeine Alternative könnte die Verwendung von Erweiterungsmethoden sein, aber ich denke nicht, dass das in Ihrem Fall funktioniert, weil Sie versuchen, dem Typ ein Ereignis hinzuzufügen.

Die einzige brauchbare Alternative, die ich mir vorstellen kann, wäre, etwas wie PostSharp oder ein anderes AOP-Framework zu verwenden, um nach dem Kompilieren einige Codewebens durchzuführen.