Was ist der wahre Grund, warum der Zugriff von geschützten Mitgliedern durch eine Basis- / Geschwisterklasse verhindert wird?
Ich habe kürzlich festgestellt, dass eine Methode in einer abgeleiteten Klasse nur über eine Instanz der abgeleiteten Klasse (oder einer ihrer Unterklassen) auf die geschützten Instanzmitglieder der Basisklasse zugreifen kann:
class Base
{
protected virtual void Member() { }
}
class MyDerived : Base
{
// error CS1540
void Test(Base b) { b.Member(); }
// error CS1540
void Test(YourDerived yd) { yd.Member(); }
// OK
void Test(MyDerived md) { md.Member(); }
// OK
void Test(MySuperDerived msd) { msd.Member(); }
}
class MySuperDerived : MyDerived { }
class YourDerived : Base { }
Ich konnte diese Einschränkung umgehen, indem ich der Basisklasse eine statische Methode hinzufügte, da die Methoden von Base auf Base.Member zugreifen dürfen und MyDerived diese statische Methode aufrufen kann.
Ich verstehe immer noch nicht den Grund für diese Einschränkung. Ich habe ein paar verschiedene Erklärungen gesehen, aber sie erklären nicht, warum MyDerived.Test () weiterhin auf MySuperDerived.Member zugreifen darf.
Die grundsätzliche Erklärung:"Geschützt" bedeutet, dass nur auf diese Klasse und ihre Unterklassen zugegriffen werden kann. YourDerivedkönnte Überschreiben Sie Member () und erstellen Sie eine neue Methode, auf die nur YourDerived und seine Unterklassen zugreifen dürfen. MyDerived kann das überschriebene yd.Member () nicht aufrufen, weil es keine Unterklasse von YourDerived ist, und es kann b.Member () nicht aufrufen, weil b möglicherweise tatsächlich eine Instanz von YourDerived ist.
OK, aber warum kann MyDerived dann msd.Member () aufrufen? MySuperDerived konnte Member () überschreiben, und diese Überschreibung sollte nur MySuperDerived und seinen Unterklassen zugänglich sein, oder?
Sie wissen erst zur Laufzeit, ob Sie ein überschriebenes Mitglied aufrufen oder nicht. Und wenn das Mitglied ein Feld ist, kann es sowieso nicht überschrieben werden, aber der Zugriff ist weiterhin verboten.
Die pragmatische Erklärung:Andere Klassen fügen möglicherweise Invarianten hinzu, die Ihre Klasse nicht kennt, und Sie müssen deren öffentliche Schnittstelle verwenden, damit sie diese Invarianten verwalten können. Wenn MyDerived direkt auf geschützte Mitglieder von YourDerived zugreifen kann, können diese Invarianten zerstört werden.
Mein gleicher Einwand gilt hier. MyDerived weiß auch nicht, welche Invarianten MySuperDerived hinzufügen könnte - es könnte von einem anderen Autor in einer anderen Assembly definiert worden sein - warum kann MyDerived dann direkt auf seine geschützten Mitglieder zugreifen?
Ich habe den Eindruck, dass diese Beschränkung der Kompilierungszeit ein irrtümlicher Versuch ist, ein Problem zu lösen, das wirklich nur zur Laufzeit gelöst werden kann. Aber vielleicht fehlt mir etwas. Hat jemand ein Beispiel für ein Problem, das dadurch verursacht wird, dass MyDerived über eine Variable vom Typ YourDerived oder Base auf die geschützten Mitglieder von Base zugreift?nicht gibt es bereits beim Zugriff über eine Variable vom Typ MyDerived oder MySuperDerived?
-
UPDATE: Ich weiß, dass der Compiler nur die Sprachspezifikation befolgt. Was ich wissen möchte, ist der Zweck dieses Teils der Spezifikation. Eine ideale Antwort wäre: "Wenn MyDerived YourDerived.Member () aufrufen könnte, würde $ NIGHTMARE passieren, aber das kann nicht passieren, wenn MySuperDerived.Member () aufgerufen wird, weil $ ITSALLGOOD."