Typsichere diskriminierte Vereinigungen in C # oder: Wie kann die Anzahl der Implementierungen einer Schnittstelle begrenzt werden?

7

Zuerst, Entschuldigung für die lange Post. Grundsätzlich ist meine Frage:

Ich versuche, den folgenden F # diskriminierten Vereinigungstyp in C # zu reproduzieren:

%Vor%

Kann jemand eine einfachere schnittstellenbasierte Lösung vorschlagen als die folgenden?

%Vor%

Alle meine Algorithmen erkennen diese drei Beziehungstypen und nur diese. Daher muss ich weitere Implementierungen von IRelation durch Dritte (d. h. andere Assemblies) verhindern.

  

Fußnote: Für einige könnte es vorkommen, dass wenn ich meine Schnittstelle und Algorithmen bezüglich Objektorientierung / Polymorphismus richtig verstanden habe, sollte es keine Rolle spielen Die Implementierung der Partner wird in meine Algorithmusmethoden eingefügt, solange die Schnittstelle korrekt implementiert ist. Dies ist eine gültige Kritik. Aber nehmen wir einfach an, dass ich in diesem Fall einen funktionaleren Programmierstil gegenüber der strengen Objektorientierung bevorzuge.

Meine beste Idee ist bisher, alle oben genannten Typen als internal zu deklarieren (dh sie werden niemals direkt von Außenstehenden gesehen werden) und einen Proxy-Typ Relation zu erstellen, der der einzige sichtbare Typ für Dritte ist:

%Vor%

Bis jetzt ist alles gut, aber es wird komplizierter ...

  • ... wenn ich Factory-Methoden für die konkreten Relationstypen verfügbar mache:

    %Vor%
  • ... immer wenn ich einen Algorithmus offenlege, der an Relationstypen arbeitet, weil ich vom / zum Proxytyp abbilden muss:

    %Vor%
stakx 12.03.2011, 14:04
quelle

3 Antworten

13

Wenn Sie die Schnittstelle -Implementierungen einschränken, handelt es sich nicht wirklich um eine Schnittstelle (die eine Implementierung (Substitution) akzeptieren sollte, z. B. Dekoratoren). Daher kann ich das nicht empfehlen.

>

Beachten Sie auch, dass mit einer kleinen Ausnahme von Generika das Behandeln einer Struktur als Schnittstelle zum Boxen führt.

Damit bleibt ein interessanter Fall übrig; eine abstrakte Klasse mit einem privaten -Konstruktor und einer bekannten Anzahl von Implementierungen als verschachtelte Typen , was bedeutet, dass sie Zugriff auf den privaten Konstruktor haben.

Jetzt steuern Sie die Subtypen, Boxen ist kein Problem (wie es eine Klasse ist), und es gibt weniger Substitutionserwartung.

    
Marc Gravell 12.03.2011, 14:23
quelle
6

Ich denke, Ihr allgemeiner Ansatz geht in die richtige Richtung, aber es sieht so aus, als könnten Sie Ihren Code mit abstrakten Klassen vereinfachen:

%Vor%

Äußere Assemblies können alle Mitglieder der Relation -Klasse außer des internen Konstruktors sehen - was von außen zeigt, dass die Klasse keine Konstruktoren definiert hat, also ist das nicht möglich für Assemblies von Drittanbietern, um ihre eigenen Implementierungen zu definieren.

    
Juliet 13.03.2011 05:43
quelle
3

Ich würde mit der Idee gehen, die auf enum basiert. Tatsächlich würde ich diese Lösung auch in F # verwenden. Da du immer nur zwei Argumente hast, brauchst du keine diskriminierte Vereinigung:

%Vor%

Wenn Sie diskriminierte Union in C # codieren möchten, ist es wahrscheinlich die beste Option, die abstrakte Basisklasse und dann die geerbte Klasse für jeden Fall (mit zusätzlichen Feldern) zu verwenden. Da Sie nicht beabsichtigen, es durch Hinzufügen neuer Unterklassen zu erweitern, können Sie tag enum definieren, das alle möglichen Subtypen auflistet (so dass Sie "pattern matching" einfach mit switch für das Tag implementieren können) ).

    
Tomas Petricek 12.03.2011 16:56
quelle