Dies ist eine philosophische Frage zu C # -Fundamenten: Ich frage mich, wie nahe eine Schnittstelle durch eine vollständig abstrakte Klasse simuliert werden kann. Angenommen, wir haben folgende Schnittstelle:
%Vor%Und folgende abstrakte Klasse:
%Vor%Sie haben so viel gemeinsam, nicht wahr? Die Unterschiede, die ich kenne, sind:
Können diese Einschränkungen durch Reflexion oder ähnliches übersprungen werden?
Ich erkenne, dass Interface und abstrakte Klasse in root unterschiedlich sind: interface deklariert eine Bedingung von " kann sich wie verhalten", abstrakte Klasse - " ist eine Art ", aber auch dies scheint so nahe zu sein, dass geringe Unterschiede zwischen diesen Entitäten diskutiert werden müssen. Diese Frage kann sogar wie "Was würden Sie tun, um eine Schnittstelle in C ++ zu machen" klingen.
Können diese Einschränkungen durch Reflexion oder ähnliches übersprungen werden?
Nein. Abstrakte Klassen und Schnittstellen sind unterschiedliche Konzepte auf der Ebene der Common Language Runtime. Daher ist es in C # auch nicht möglich, weil es letztendlich begrenzt ist durch CLR's Grenzen.
Ich frage mich, wie nahe eine Schnittstelle durch vollständig abstrakte Klasse simuliert werden kann.
Es ist machbar, erfordert jedoch Unterstützung (oder "Erlaubnis") von der zugrunde liegenden Ausführungsumgebung (sei es physisch oder verwaltet).
In der Vergangenheit habe ich eine Sprache entworfen, die abstrakte Klassen für Interfaces komplett ersetzt. Und ja, es hat die Mehrfachvererbung solcher "Interfaces" unterstützt. Die Implementierungseigenschaften sind jedoch die Mühe wahrscheinlich nicht wert. Die Hauptunterscheidung bestand darin, dass eine interne eingebettete Instanz der geerbten abstrakten Klasse in der Instanz der implementierenden Klasse beibehalten werden musste und eine Kette von this
-Zeigern beibehalten werden musste. Unnötig zu sagen, es war eine freudige Erfahrung: -)
Wenn ich also Ihre Frage verstehe, haben Sie zwei verwandte Probleme.
Der erste ist wirklich "Was ist der Unterschied zwischen einer abstrakten Klasse und einer Schnittstelle"; Die zweite lautet: "Kann ich in C # die Unterschiede umgehen, indem ich eine abstrakte Klasse ohne konkrete Methoden wie eine Schnittstelle ausfühle?".
Die erste Frage ist im Link von @ Todd Schiller gut beantwortet.
Die zweite Frage ist komplizierter.
Sie könnten möglicherweise eine Build-Time-Aufgabe erstellen, um alle abstrakten Klassen ohne konkrete Implementierungen in eine Schnittstelle zu konvertieren. Ich habe es nie versucht - weil ich keinen Nutzen sehe und viele, viele Nachteile.
Der größte Nachteil ist, dass Ihr Code schwieriger zu debuggen und zu warten ist. Entwickler erfahren, wann eine abstrakte Klasse erstellt werden soll und wann eine Schnittstelle erstellt werden soll. es ist ein etabliertes, allgemein anerkanntes Idiom. Neue Entwickler, die an Ihrer Codebasis arbeiten, werden eine Menge neuer Dinge lernen - und die Einführung einer neuen Denkweise über Interfaces und abstrakte Klassen wird diesen Prozess härter und länger machen.
Beim Debuggen Ihrer Anwendung wird ein Entwickler, der eine abstrakte Klasse im Quellcode sieht - aber im Laufzeitcode sieht, dass es sich tatsächlich um eine Schnittstelle handelt - wahrscheinlich verwirrt sein und seine Zeit damit verbringen, herauszufinden, warum dies geschieht , anstatt den echten Fehler aufzuspüren.
Soweit ich sehen kann, gibt es keinen offensichtlichen Nutzen.
Für mich läuft es wirklich auf ihre Fähigkeiten hinaus. Eine Schnittstelle wird NIEMALS eine Implementierung für irgendeinen ihrer Operationen bereitstellen; es verspricht nur, dass jeder, der es benutzt, etwas bereitstellen muss. Eine abstrakte Klasse kann Implementierungen für beliebige ihrer Operationen bereitstellen, die im Ermessen ihrer Unterklassen überschrieben werden können. Und nein, Sie werden niemals in der Lage sein, diese Beschränkungen durch Reflexion zu übergehen, da sie für die Sprache selbst von zentraler Bedeutung sind.
Was die Verwendung einer abstrakten Klasse anstelle einer Schnittstelle betrifft, kommt es noch einmal darauf an, was Sie erreichen müssen. Wenn Sie eine Basisimplementierung bereitstellen müssen, müssen Sie eine abstrakte Klasse verwenden - andernfalls gehen Sie mit der Schnittstelle.
Einige der anderen Unterschiede, die Sie bereits erwähnt haben. Sie können mehrere Schnittstellen in C # implementieren, aber Sie können immer nur von einer einzigen Klasse (abstrakt oder nicht) ableiten.
Es kann heiß sein Thema im Zusammenhang mit OOPS-Philosophie .. wie wir wissen, hat es wenige technische Unterschied wie Schnittstelle hat keinen Konstruktor, und geerbte Klasse muss alle Methoden usw. implementieren, aber ich mag es mit real zu diskutieren Weltszenario. Eigentlich denke ich Interface ist ein Vertrag zwischen einem Objekt mit seinem Verbraucher. Aber abstrakte Klasse ist kein Vertrag, obwohl beide verwenden können, um "liskov Substitutionsprinzip" zu erreichen. Ich mag zwei Situationen im wirklichen Leben auflisten ..
1.) Stellen Sie sich eine Zeichenanwendung vor, die Form, Rechteck, Quadrat usw. enthalten kann. Hier kann die Form eine abstrakte Klasse oder ein Schnittstellentyp sein. Aber wenn ich sicherstellen muss, dass jedes Objekt in meiner Anwendung einen Zustand haben muss, während es instanziiert wird. Ich kann diese Möglichkeit mit der Schnittstelle nicht erreichen, so dass die Schnittstelle den Zustand eines Objekts nicht halten kann.
2.) Wenn meine Shapes gemeinsame Werte teilen (ein statischer Wert), kann ich das nicht mit der Schnittstelle erreichen, also denke ich, dass die abstrakte Klasse sowohl den Status als auch das Verhalten beibehalten kann
aber unter Berücksichtigung der Schnittstelle ist es eine Übereinstimmung über das Verhalten, schauen ein echtes Beispiel, Tiere und Vögel, beide diese Objekte haben ein ähnliches Verhalten, aber wir können nicht sagen, dass sie gemeinsame Eigenschaften teilen, sowohl Vögel und Tiere können gehen, weinen, essen , die Ausführung dieser Aktionen ist völlig anders. in unserer Programmierschnittstelle ist ein idealer Kandidat in einer Situation, in der Sie nur Zustimmung brauchen, brauchen Sie keine Staaten. Die gute Sache ist, dass ein Konsumobjekt jedes andere Objekt ersetzen kann, das diese Übereinstimmung erfüllt, D I ist ein bestes Beispiel.
Tags und Links c# inheritance design oop interface