5 Stimmen

Vorschläge benötigt: Alternative zum Überladen von "is" und "as" Operatoren in .NET

Ich hoffe, dass diese Frage nicht als zu subjektiv angesehen wird - ich erwarte nicht wirklich eine endgültige Antwort, aber ich hoffe, dass die Meinung der anderen mir zumindest dabei hilft, mir meine eigene zu bilden.

Ich implementiere ein benutzerdefiniertes Typsystem, das eine Obermenge des klassischen OOP-Typsystems ist. In diesem Typsystem können Objektinstanzen zur Laufzeit kombiniert werden, um neue Instanzen zu bilden, wobei die individuellen Identitäten erhalten bleiben.

Dieser Code:

var p = new Person();
var pa = new Partner(p);

...führt zu einem einzigen kombinierten Objekt, wobei "p" und "pa" verschiedene OOP-konforme Sichten darauf sind. D.h., die Änderung eines Eigenschaftswertes in einer der Ansichten wirkt sich sofort auf jede andere Ansicht aus, die diese Eigenschaft ebenfalls enthält.

Das alles funktioniert gut und schön, aber es fehlen zwei wichtige APIs für die Abfrage von Typ-Identitäten. Ich würde wirklich gerne in der Lage sein, solchen Code zu schreiben:

if (p is Partner)
{
    (p as Partner).SomePartnerProperty = "...";
}

Das funktioniert natürlich nicht, weil das Verhalten von "is"- und "as"-Operatoren nicht über das hinaus überladen/erweitert werden kann, was die OOP-Regeln von .NET vorschreiben. Nichtsdestotrotz brauche ich diese Funktion in meinem Typsystem.

Mein erster Gedanke war, generische Erweiterungsmethoden zu verwenden, die sich an alle Instanzen meines Typsystems anhängen würden:

public static bool Is<T>(this BaseType target) where T : BaseType { ... }
public static T As<T>(this BaseType target) where T : BaseType { ... }

Abgesehen von der Frage des Namenskonflikts in Sprachen, die Groß- und Kleinschreibung nicht berücksichtigen, scheint dies in Bezug auf die Funktionalität in Ordnung zu sein:

if (p.Is<Partner>())
{
    p.As<Partner>().SomePartnerProperty = "...";
}

Ich muss mich jedoch fragen, ob dies wirklich die schönste und bequemste API ist, die man sich ausdenken kann.

Was würden Sie mir raten, um diese beiden Operatoren so zu implementieren, dass sie sich im Anwendungscode natürlich anfühlen?

UPDATE : Für alle, die sich über den Zweck eines solchen Systems wundern... Im Grunde genommen fällt jeder Typ in eine von zwei Kategorien: Identität ou Rolle . In dem oben genannten Beispiel ist Person eine Identität (durch Design), während Partner eine Rolle ist (wiederum durch Design - es hätte auch anders gestaltet werden können). Die Grundregel dieses Typsystems ist, dass eine beliebige Anzahl von Rollen mit einer beliebigen Identität zusammengesetzt werden kann, während die Identität selbst nur mit einer höheren Identität zusammengesetzt werden kann (z. B. kann eine Person zu einem Kontakt, aber niemals zu einem Unternehmen werden). Ein solches Typensystem ermöglicht es Anwendungen, z. B. mit Partnerobjekten transparent umzugehen, unabhängig davon, welche Identität sie haben (z. B. Person, Firma, Bank usw.).

0voto

tster Punkte 17284

Moment mal... Ich sehe nicht, was an normalem OO-Code falsch ist (es sei denn, Sie haben Tonnen von Klassen)

interface IPartner {...}
interface IPerson {...}
interface ICompany {...}

class Person : IPerson {...}
class PersonPartner : Person, IPartner {...}
class Company : ICompany {...}
class CompanyPartner : Company, IPartner {...}

Natürlich wäre dies mit Mehrfachvererbung einfacher...

0voto

Jordão Punkte 53117

Ich habe in letzter Zeit viel über diese Konzepte nachgedacht, und über Traits in C# . Ich denke, die Idee, die Sie für die Typentest-Erweiterungsmethoden haben, wird nicht viel besser als das (es ist fast genau das, was ich mir ausgedacht habe). In Anlehnung an die Terminologie von Perl 6 Rollen rufe ich Ihre Is Methode Does stattdessen. Aber ich würde die As unverändert.

Aber ich glaube nicht, dass diese Verwendung für das, was Sie zu erreichen versuchen, natürlich ist:

var p = new Person(); 
var pa = new Partner(p); 

Es sieht nicht so aus, als würden sie auf dieselbe Instanz verweisen. Jetzt leihen wir uns von Scala vielleicht stattdessen so etwas wie das hier?

var p = new Person(); 
var pa = p.With<Partner>(); 

Wie auch immer, haben Sie Ihr API fertiggestellt? Ist sie Open-Source?

-1voto

Bob Punkte 93584

Für mich sieht es aus wie ein Partner ist nicht a Person sondern ein Partner tut haben eine Person . Für mich würde die Schnittstelle Sinn machen als

var p = new Person();
var pa = new Partner(p);

pa.SomePartnerProperty = "...";
pa.Person.SomePersonProperty = "...";

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X