Laden...

ObservableCollection protected PropertyChanged

Erstellt von Palladin007 vor 10 Jahren Letzter Beitrag vor 9 Jahren 3.806 Views
Palladin007 Themenstarter:in
2.079 Beiträge seit 2012
vor 10 Jahren
ObservableCollection protected PropertyChanged

Hi,

im Laufe eines kleinen Projektes habe ich mir die ObservableCollection-Klasse mal genauer angeschaut und dabei ist mir aufgefallen, dass (zumindest in den Metadaten) das PropertyChanged Event nur protected ist.

Das hat mich insofern schon mal verwundert, weil das dank dem Interface INotifyPropertyChanged ja public sein muss.

Also habe ich mir mal den Source-Code von der Klasse mal angeschaut und habe folgendes gefunden:

public class ObservableCollection<T> : Collection<T>, INotifyCollectionChanged, INotifyPropertyChanged
{
        // [...]

        event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
        {
            add
            {
                PropertyChanged += value;
            }
            remove
            {
                PropertyChanged -= value;
            }
        }

        // [...]

        protected virtual event PropertyChangedEventHandler PropertyChanged;

        // [...]
}

Kann mir jemand erklären, wo der Sinn davon liegt?

Ein public Event ist ja automatisch auch für erbende Klassen sichtbar, warum trennt man das dann nochmal auf?

Gruß

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

16.835 Beiträge seit 2008
vor 10 Jahren

Weil Indexer wie
event PropertyChangedEventHandler (**INotifyPropertyChanged.PropertyChanged**){red}
genau so definiert werden müssen und nicht vererbt werden können.

Oder worauf bezieht sich Deine Frage?

Palladin007 Themenstarter:in
2.079 Beiträge seit 2012
vor 10 Jahren

Ich meine, dass folgendes auch ausreichen würde:

public virtual event PropertyChangedEventHandler PropertyChanged;

Das sollte meines Erachtens nach das Gleiche sein, oder sehe ich das falsch?

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

16.835 Beiträge seit 2008
vor 10 Jahren

Nein, eben nicht. Siehst Du falsch.
Nicht nur, dass das INotify in der Form nicht funktionieren würde; public hat auch eine andere Bedeutung als protected.
Und aussehnstehende sollen von dem Event ja gar nichts wissen, weils nur die privaten Eigenschaften interessiert.

Palladin007 Themenstarter:in
2.079 Beiträge seit 2012
vor 10 Jahren

Aber durch das Interface ist es doch sowieso public, ich muss ja nur über das Interface darauf zugreifen:

((INotofyPropertyChanged)collection).PropertyChanged += Method;

Nicht nur, dass das INotify in der Form nicht funktionieren würde

Warum würde es in der Form nicht funktionieren?

Das mit dem virtual funktioniert auch, zumindest bekomme ich keinen Syntax-Fehler, wirklich getestet habe ich es nicht:

class test : INotifyPropertyChanged
{
    public virtual event PropertyChangedEventHandler PropertyChanged;
}
class test2 : test
{
    public override event PropertyChangedEventHandler PropertyChanged
    {
        add
        {
            base.PropertyChanged += value;
            // Tue noch was anderes
        }
        remove
        {
            base.PropertyChanged -= value;
            // Tue noch was anderes
        }
    }
}

Das würde sogar reichen, wäre aber komplett sinnfrei:

public override event PropertyChangedEventHandler PropertyChanged;

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

16.835 Beiträge seit 2008
vor 10 Jahren

Du vergisst immernoch das explizite **INotifyPropertyChanged.**PropertyChanged
Gleiches ist zB auch bei WPFs IDataError-Implementierung zu finden.

Siehe dazu auch Property-Name "in" dem ein Punkt (".") vorkommt [=> interface-explizite Implementierung d. Property]

Palladin007 Themenstarter:in
2.079 Beiträge seit 2012
vor 10 Jahren

Das habe ich nicht vergessen, aber ich verstehe nicht, wozu das gut ist.

Nicht, wozu die explizite Implementierung eines Interfaces gut ist, das weiß ich. Ich verstehe nicht, was hier der Sinn ist.

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

16.835 Beiträge seit 2008
vor 10 Jahren

Das hat Coffebean im verlinkten Thread erklärt:

Damit sagst du, dass ein Property/eine Methode (oder was auch immer vom Interface angeboten wird) absolut nur über das Interface angesprochen werden kann.

Sonst könnte man "versehentlich" auch über die Implementierung darauf zugreifen. Das ist mit der expliziten implementierung nicht möglich.

D
96 Beiträge seit 2012
vor 10 Jahren

Es ist nunmal (design-technisch) gewollt, dass die Interfaceimplementierung explizit ist und explizite Implementierungen können nicht als virtual deklariert werden. Es ist somit der einzige Weg eine Methode sowohl explizit als auch virtual zu implementieren.

49.485 Beiträge seit 2005
vor 9 Jahren

Hallo Palladin007,

wenn man die Situation etwas verallgemeinert, kann ein öffentliches statisches in Verbindung mit einem geschützten virtuellen Member durchaus Sinn machen. Zum Beispiel sind in Collection<T> - einer Basisklasse, von der man spezifische eigene Collections ableiten kann - nicht die öffentlichen Methoden wie Add und Insert virtuell, sondern die geschützten wie InsertItem.

Dafür gibt es aus meiner Sicht zwei Gründe: Zum einen kann die Parameterprüfung (z.B. ArgumentOutOfRange) in der statischen Methode dadurch nicht umgangen werden und zum anderen wird die ähnliche Funktionalität (hier: Insert und Add) auf eine gemeinsame Methode (hier: InsertItem) abgebildet, so dass weniger Methoden überschrieben werden müssen und das Verhalten zudem konsistent ist.

Es kann also durchaus Fälle geben, in denen so eine Konstruktion Sinn macht.

Im dem von dir genannten Fall, kann ich den Sinn allerdings auch nicht erkennen. Insbesondere, da in der konkrete Implementierung keine der genannten Vorteile zu erkennen sind.

Sicher, durch die interface-explizite Implementierung kann das Event nur über das Interface abonniert werden und nicht direkt über die ObservableCollection. Aber ob das der beabsichtigte Effekt ist, oder nur einer, der für die Trennung in statischen und virtuellen Teil in Kauf genommen wird, vermag ich nicht zu beurteilen. Ich sehe im konkreten Fall keinen zwingenden Grund, warum eine interface-explizite Implementierung für sich genommen gewünscht sein könnte.

Im Kern teile ich deine Verwunderung und kann nur spekulieren. Ich könnte mir vorstellen, dass hier aus Gründen der Einheitlichkeit ein Implementierungsmuster verwendet wird, dass an anderen Stellen seinen Nutzen hat, auch wenn es diesem konkreten Fall nicht so ist. Beziehungsweise noch nicht so ist, also das Muster verwendet wird, damit man offen ist, in Zukunft von den Vorteilen Gebrauch zu machen. Zum Beispiel wenn in dem statischen Teil später noch Prüfungen oder anderes unumgehbares Verhalten eingebaut werden.

herbivore