Verwendung von eingeschränkten Generika anstelle von Schnittstellen - Nachteile?

8

Sagen wir, ich habe

%Vor%

Manchmal, anstatt nur

zu sagen %Vor%

Am Ende mache ich

%Vor%

oder vielleicht sogar

%Vor%

um das Boxen oder Kopieren von struct s zu vermeiden.

Es funktioniert gut und alles, aber gibt es irgendwelche Nachteile, von denen ich nichts weiß (abgesehen von einem vernachlässigbaren Anstieg der Speichernutzung)? Ist das eine akzeptierte Praxis, oder wird es aus irgendeinem Grund, von dem ich vielleicht nichts weiß, entmutigt?

    
Mehrdad 03.12.2011, 20:33
quelle

2 Antworten

4

Generics kommt mit einem kleinen Preis, meist um größere Codegröße. Ein letzte Blog-Post von Joe Duffy gibt einen ziemlich detaillierten Blick auf diese. Aber im Allgemeinen, für häufig verwendeten Code Boxen zu vermeiden, ist eine gute Sache und wahrscheinlich mehr wert erzeugten Bytecode (in der Praxis bedeutet dies etwas höhere Speichernutzung und mehr Arbeit für den JIT).

    
bobbymcr 03.12.2011, 20:39
quelle
1

Interface-Constraints sind wunderbar, aber es gibt eine wichtige Einschränkung: Während es für Strukturen möglich ist, entweder unveränderliche Semantik, Mutable-Value-Semantik oder veränderbare Referenzsemantik () zu haben, haben Boxed-Strukturen, wenn sie veränderbar sind, immer Referenzsemantik . Obwohl die Semantik veränderbarer Werte oft nützlich ist ( *), kann es schwierig sein, sie mit Generika gut zu kombinieren. Denken Sie sogar an eine Frage, ob die Parameter an der Matrix multiplizieren Sie Liste sollte durch Verweis oder durch Wert übergeben werden: Wenn der generische Typ ist ein Werttyp, sollten die Parameter wahrscheinlich durch Verweis übergeben werden; Wenn es sich um einen Klassentyp handelt, sollten sie nach Wert übergeben werden.

Als weiteres Beispiel für die Referenz / Wert-Unterscheidung sei angenommen, dass eine Methode eine Matrix hat und was sie haben möchte, ist eine Matrix, die genau wie die alte ist, außer mit den Elementen (0,0) und (1,1). Zeroed, und es wird nicht mehr die ursprüngliche Matrix benötigen. Wenn die Matrix ein änderbarer Wertetyp mit einer einstellbaren indizierten Eigenschaft ist, kann die Methode einfach ohne unerwünschte Nebenwirkungen in die Elemente (0,0) und (1,1) schreiben; Wenn es sich um einen veränderlichen Referenztyp handelt, müsste die Routine wahrscheinlich zuerst einen defensiven Klon erstellen (ick); Wenn es ein unveränderlicher Typ ist, muss es möglicherweise für jede Änderung eine neue Instanz erstellen (ick). Die Verwendung eines Werttyps kann eine sauberere Semantik bieten, kann jedoch zu unerwarteten Nebeneffekten führen, wenn das System Codetransformationen wie Boxen ausführt, die Semantiken vom Werttyp in Referenzsemantiken oder gebrochene Semantiken ändern.

(*) Eine Struktur, die einfach veränderbare Felder exponiert, zeigt eine sehr saubere Semantik vom veränderbaren Werttyp. Angesichts der Erklärungen:

%Vor%

Wenn man sich nur den obigen Code ansieht, kann man feststellen, dass der angegebene Methodenaufruf sich auf y.value auswirkt, aber weder auf x.value noch auf den Wert von y.value nach der Rückkehr des Methodenaufrufs. Wenn dagegen valueStruct stattdessen eine Klasse ist, gibt es keinen Hinweis darauf, was der angegebene Aufruf für x.value tun könnte, und auch nicht, ob sich der y.value zu irgendeiner willkürlichen zukünftigen Zeit ändern könnte.

Obwohl Strukturen mit exponierten Feldern eine Semantik mit veränderbarem Wert implementieren, ist es für Strukturen möglich, eine veränderbare Referenzsemantik zu implementieren, wenn sie ein unveränderbares Feld des Klassentyps enthalten und wenn die einzigen Mutatoren, die sie exponieren, auf dieses Feld einwirken. Dies kann manchmal ein nützliches Muster sein, obwohl es etwas eingeschränkt ist, weil die C # - und vb-Compiler Operationen verbieten, die so aussehen, als ob sie versuchen würden, die Struktur zu verändern (würden aber das Klassenobjekt, das eine Referenz enthält, wirklich mutieren). Beachten Sie, dass unveränderliche Strukturen mit veränderbarer Referenzsemantik mit einem nicht standardmäßigen Konstruktor initialisiert werden müssen, um nützlich zu sein. Solche Strukturen, die über die Standardinitialisierung erstellt werden, sind im Allgemeinen kaputt und nutzlos. im besten Fall sind sie nicht voneinander zu unterscheiden.

    
supercat 07.12.2011 00:29
quelle