Ich habe so etwas:
%Vor% Ich muss SomeDataBlob
public angeben, damit es als Mitglied der öffentlichen Schnittstellenmethode ExternalPlugin.DoStuff
verwendet werden kann. Ich möchte jedoch nicht zulassen, dass Clients von dieser Klasse erben und somit anfällig für das Problem der spröden Basisklasse sind. (Alle Derivate dieser Klasse sollten in derselben Baugruppe aufbewahrt werden)
Das Markieren der Klasse sealed
geht zu weit, weil ich glaube, dass das Entfernen von sealed
eine Änderung der API ist; Und selbst wenn dies nicht der Fall ist, können die SomeDataBlobV2
clients nach dem Versand immer noch das Falsche tun und direkt von SomeDataBlob
erben.
Gibt es eine Möglichkeit, diese Art von Muster zu erzwingen?
Machen Sie die Klasse intern und geben Sie stattdessen eine Schnittstelle frei. Verwenden Sie dann das Factory-Muster, um die korrekte Implementierung zu erstellen.
%Vor%Sie verbergen die Implementierung, aber geben dem Benutzer immer noch Zugriff auf alles. Sie machen sogar Komponententests für Ihre Benutzer einfacher;)
Bearbeiten (auf einen Kommentar des OP antworten)
Was ich effektiv möchte, ist eine Methode, die einige Parameter annimmt. Ich möchte in der Lage sein, Parameter hinzuzufügen, die die Hauptanwendung in einer zukünftigen Version bereitstellen kann, wenn die API ohne Clients zu brechen. Aber ich möchte nicht, dass Clients in der Lage sind, Instanzen der "Parameter" -Klasse / -Schnittstelle zu erstellen oder anderweitig mit ihr zu interagieren, anstatt eine Instanz davon als Parameter zu erhalten
Anstatt die APIs zu verstecken, können Sie sicherstellen, dass alle an Ihre Bibliothek übergebenen Objekte von Ihrer Assembly stammen:
%Vor%Bearbeiten2
Habe gerade bemerkt, dass @RQDQ diese Lösung bereits bereitgestellt hat (habe es bei der Beantwortung Ihres Kommentars nicht bemerkt). Wenn das die Lösung ist, die Sie wollen, akzeptieren Sie stattdessen seine Antwort.
Ich habe so etwas:
%Vor%Ich muss %code% public angeben, damit es als Mitglied der öffentlichen Schnittstellenmethode %code% verwendet werden kann. Ich möchte jedoch nicht zulassen, dass Clients von dieser Klasse erben und somit anfällig für das Problem der spröden Basisklasse sind. (Alle Derivate dieser Klasse sollten in derselben Baugruppe aufbewahrt werden)
Das Markieren der Klasse %code% geht zu weit, weil ich glaube, dass das Entfernen von %code% eine Änderung der API ist; Und selbst wenn dies nicht der Fall ist, können die %code% clients nach dem Versand immer noch das Falsche tun und direkt von %code% erben.
Gibt es eine Möglichkeit, diese Art von Muster zu erzwingen?
Soweit ich weiß, sind Schnittstellen dafür der richtige Weg. Es wäre eine Änderung der API, aber es würde bedeuten, dass Sie tun könnten, was Sie wollen.
%Vor%Und dann, damit die Objekte das Fabrikmuster verwenden, z. B.
%Vor%SomeDataBlob kann nicht vererbt werden, da sein einziger Konstruktor intern ist. Wenn Sie versuchen, eine abgeleitete Klasse in einer Clientanwendung zu implementieren:
%Vor%Sie erhalten den folgenden Fehler:
Der Typ 'ClassLibrary1.SomeDataBlob' hat keine Konstruktoren definiert
Es scheint, dass Sie Ihr eigenes Problem gelöst haben.
Was ich tun würde, ist eine Art Factory-Klasse zu erstellen, die eine Schnittstelle zur Verfügung stellt, die eine Instanz jeder Version für die spezifische API, die Ihr Client verwendet, übergibt und die Implementierung mit einer internen Klasse versteckt.
Sie können Constraints auch verwenden, um die Verwendung zu vereinfachen. Dann kann der Client einfach den Objekttyp eingeben, nach dem er sucht
%Vor%Wenn Sie nicht versiegelt sind und keine Klassen verwenden, können Sie dies zur Laufzeit erzwingen. Überprüfen Sie an der API-Grenze die beteiligten Klassen und stellen Sie sicher, dass sie von Ihrer Assembly stammen.
Ein einfaches Beispiel:
%Vor%Machen Sie die Klasse intern und geben Sie stattdessen eine Schnittstelle frei. Verwenden Sie dann das Factory-Muster, um die korrekte Implementierung zu erstellen.
%Vor%Sie verbergen die Implementierung, aber geben dem Benutzer immer noch Zugriff auf alles. Sie machen sogar Komponententests für Ihre Benutzer einfacher;)
Bearbeiten (auf einen Kommentar des OP antworten)
Was ich effektiv möchte, ist eine Methode, die einige Parameter annimmt. Ich möchte in der Lage sein, Parameter hinzuzufügen, die die Hauptanwendung in einer zukünftigen Version bereitstellen kann, wenn die API ohne Clients zu brechen. Aber ich möchte nicht, dass Clients in der Lage sind, Instanzen der "Parameter" -Klasse / -Schnittstelle zu erstellen oder anderweitig mit ihr zu interagieren, anstatt eine Instanz davon als Parameter zu erhalten
Anstatt die APIs zu verstecken, können Sie sicherstellen, dass alle an Ihre Bibliothek übergebenen Objekte von Ihrer Assembly stammen:
%Vor%Bearbeiten2
Habe gerade bemerkt, dass @RQDQ diese Lösung bereits bereitgestellt hat (habe es bei der Beantwortung Ihres Kommentars nicht bemerkt). Wenn das die Lösung ist, die Sie wollen, akzeptieren Sie stattdessen seine Antwort.
Soweit ich weiß, sind Schnittstellen dafür der richtige Weg. Es wäre eine Änderung der API, aber es würde bedeuten, dass Sie tun könnten, was Sie wollen.
%Vor%Und dann, damit die Objekte das Fabrikmuster verwenden, z. B.
%Vor%Was ich tun würde, ist eine Art Factory-Klasse zu erstellen, die eine Schnittstelle zur Verfügung stellt, die eine Instanz jeder Version für die spezifische API, die Ihr Client verwendet, übergibt und die Implementierung mit einer internen Klasse versteckt.
Sie können Constraints auch verwenden, um die Verwendung zu vereinfachen. Dann kann der Client einfach den Objekttyp eingeben, nach dem er sucht
%Vor%SomeDataBlob kann nicht vererbt werden, da sein einziger Konstruktor intern ist. Wenn Sie versuchen, eine abgeleitete Klasse in einer Clientanwendung zu implementieren:
%Vor%Sie erhalten den folgenden Fehler:
Der Typ 'ClassLibrary1.SomeDataBlob' hat keine Konstruktoren definiert
Es scheint, dass Sie Ihr eigenes Problem gelöst haben.
Tags und Links c#