Ich möchte Ihnen meinen eigenen Ansatz vorstellen, den ich Jappi . Es gehört zu den Generatoren von Laufzeit-Proxys und abgeleiteten Klassen, die einem bestehenden Objekt oder Typ neue Funktionen hinzufügen, wie das Dynamic Proxy von Caste Project.
Sie ermöglicht es, INotifyPropertyChanged einmal in der Basisklasse zu implementieren und dann abgeleitete Klassen im folgenden Stil zu deklarieren, wobei INotifyPropertyChanged für neue Eigenschaften weiterhin unterstützt wird:
public class Animal:Concept
{
protected Animal(){}
public virtual string Name { get; set; }
public virtual int Age { get; set; }
}
Die Komplexität der Konstruktion abgeleiteter Klassen oder Proxys kann hinter der folgenden Zeile versteckt werden:
var animal = Concept.Create<Animal>.New();
Und alle INotifyPropertyChanged-Implementierungsarbeiten können wie folgt durchgeführt werden:
public class Concept:INotifyPropertyChanged
{
//Hide constructor
protected Concept(){}
public static class Create<TConcept> where TConcept:Concept
{
//Construct derived Type calling PropertyProxy.ConstructType
public static readonly Type Type = PropertyProxy.ConstructType<TConcept, Implementation<TConcept>>(new Type[0], true);
//Create constructing delegate calling Constructor.Compile
public static Func<TConcept> New = Constructor.Compile<Func<TConcept>>(Type);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(PropertyChangedEventArgs eventArgs)
{
var caller = PropertyChanged;
if(caller!=null)
{
caller(this, eventArgs);
}
}
//define implementation
public class Implementation<TConcept> : DefaultImplementation<TConcept> where TConcept:Concept
{
public override Func<TBaseType, TResult> OverrideGetter<TBaseType, TDeclaringType, TConstructedType, TResult>(PropertyInfo property)
{
return PropertyImplementation<TBaseType, TDeclaringType>.GetGetter<TResult>(property.Name);
}
/// <summary>
/// Overriding property setter implementation.
/// </summary>
/// <typeparam name="TBaseType">Base type for implementation. TBaseType must be TConcept, and inherits all its constraints. Also TBaseType is TDeclaringType.</typeparam>
/// <typeparam name="TDeclaringType">Type, declaring property.</typeparam>
/// <typeparam name="TConstructedType">Constructed type. TConstructedType is TDeclaringType and TBaseType.</typeparam>
/// <typeparam name="TResult">Type of property.</typeparam>
/// <param name="property">PropertyInfo of property.</param>
/// <returns>Delegate, corresponding to property setter implementation.</returns>
public override Action<TBaseType, TResult> OverrideSetter<TBaseType, TDeclaringType, TConstructedType, TResult>(PropertyInfo property)
{
//This code called once for each declared property on derived type's initialization.
//EventArgs instance is shared between all events for each concrete property.
var eventArgs = new PropertyChangedEventArgs(property.Name);
//get delegates for base calls.
Action<TBaseType, TResult> setter = PropertyImplementation<TBaseType, TDeclaringType>.GetSetter<TResult>(property.Name);
Func<TBaseType, TResult> getter = PropertyImplementation<TBaseType, TDeclaringType>.GetGetter<TResult>(property.Name);
var comparer = EqualityComparer<TResult>.Default;
return (pthis, value) =>
{//This code executes each time property setter is called.
if (comparer.Equals(value, getter(pthis))) return;
//base. call
setter(pthis, value);
//Directly accessing Concept's protected method.
pthis.OnPropertyChanged(eventArgs);
};
}
}
}
Es ist völlig sicher für Refactoring, verwendet keine Reflexion nach der Typkonstruktion und ist schnell genug.
0 Stimmen
Siehe stackoverflow.com/questions/1329138/ für eine compilergeprüfte Art der Implementierung von INotifyPropertyChanged. Vermeidung von Eigenschaftsnamen als magische Zeichenkette.
8 Stimmen
code.google.com/p/notifypropertyweaver kann von Nutzen sein
9 Stimmen
Obiger Link ist tot. github.com/SimonCropp/NotifyPropertyWeaver
1 Stimmen
Obwohl ich adäquate Alternativen hatte, war nichts für mein Team so schmerzlos wie die Postsharp-Lösung Domänen-Toolkit (wird mit normalem Postsharp in der kommenden v3.0 gebündelt werden, denke ich). [NotifyPropertyChanged] auf die Klasse, [NotifyPropertyChangedIgnore] auf die Requisiten zu ignorieren.
3 Stimmen
Sie könnten stattdessen DependencyObject und DependencyProperties verwenden. HA! Ich habe einen Witz gemacht.
0 Stimmen
@Codest und jetzt ist dein Link tot
7 Stimmen
@joao2fast4u github.com/Fody/PropertyChanged/wiki/
0 Stimmen
Ich stimme mit dem Auftraggeber überein. Es ist wirklich traurig, dass es das in Roslyn noch nicht gibt. Außerdem muss es eine Möglichkeit geben, zu vermerken, dass eine Eigenschaft vom Wert einer anderen abhängig ist (idealerweise mit Attributen und dem nameof-Operator).
6 Stimmen
Zu dieser Zeit war es nicht möglich, Änderungen an C# vorzunehmen, da wir ein riesiges Backlog mit Abhängigkeiten hatten. Damals, als MVVM geboren wurde, haben wir uns nicht sonderlich um die Lösung dieses Problems bemüht, und ich weiß, dass das Patterns & Practices-Team ein paar Versuche unternommen hat (daher haben Sie auch MEF als Teil dieses Forschungs-Threads erhalten). Heute denke ich, dass [CallerMemberName] die Antwort auf das obige Problem ist.
0 Stimmen
Ich glaube, @tom-gilder hat eine bessere Antwort. stackoverflow.com/a/18002490/4062881
0 Stimmen
ObservableCollection
eliminiert die Notwendigkeit der ImplementierungOnPropertyChanged
für einfache Situationen. Siehe So geht's: Erstellen und Binden an eine ObservableCollection y ObservableCollection .