Wert gegenüber Referenztypen bei Verwendung von Schnittstellen in C #

8

Ich möchte einen Typ in C # mit Wert wie Semantik erstellen. Es ist unveränderbar und hat einen geringen Speicherbedarf. Es wird jedoch meist über eine von ihm implementierte Schnittstelle erreicht. In diesem Fall müsste ein Werttyp eingerahmt werden, was bedeutet, dass der tatsächliche Wert vom Stapel auf den Heap kopiert werden müsste. Daher frage ich mich, ob es irgendeinen Vorteil gibt, einen Werttyp (struct) anstelle eines Referenztyps (class) zu verwenden?

Um meine Situation zu illustrieren, gebe ich das folgende Beispiel einer Schnittstelle I mit den Implementierungen ReferenceTypeImplementation und ValueTypeImplementation :

%Vor%

Ich würde fast ausschließlich diesen Typ mit der Schnittstelle I like

verwenden %Vor%

Gibt es einen Vorteil bei der Verwendung von ValueTypeImplementation über ReferenceTypeImplementation ?

    
brdlph 30.05.2013, 16:59
quelle

3 Antworten

10
  

Gibt es einen Vorteil bei der Verwendung von ValueTypeImplementation gegenüber ReferenceTypeImplementation?

Nicht, wenn Sie es über die Schnittstelle verwenden möchten. Wie Sie bereits erwähnt haben, wird dies den Werttyp einschließen, der jede mögliche Leistungsverbesserung negiert.

Darüber hinaus würde die Tatsache, dass Ihre erwartete Hauptverwendung über die Schnittstelle erfolgt, darauf hindeuten, dass Sie Referenzsemantiken erwarten, was wiederum darauf hindeutet, dass ein class geeigneter wäre dieser Fall.

    
Reed Copsey 30.05.2013, 17:01
quelle
2

Das Konvertieren einer Struktur in eine Schnittstelle verursacht ein Boxen. Aufruf eines implizit implementierten Mitglied in einer Struktur verursacht nicht Boxen:

%Vor%

Hier in Ihrem Fall, wenn Sie mit impliziter Implementierung / Aufruf arbeiten können, dann sind Sie besser dran mit struct, da Sie vermeiden;

(a) Boxen

(b) kein zusätzlicher Speicheraufwand (der für jede Zuweisung von Referenztypen gilt).

    
Nair 30.05.2013 17:07
quelle
0

Wenn Foo implementiert IBar , gibt es zwei Möglichkeiten, wie die Mitglieder von IBar für eine Instanz von Foo verwendet werden können:

  • Eine Referenz auf die Instanz (für Klassentypen) oder eine Referenz auf ein Heap-Objekt, das eine Kopie der Instanz enthält (für Werttypen), kann in einer Variablen vom Typ IBar

  • Die Instanz (für Werttypen) oder eine Referenz darauf (für Klassentypen) kann in einer Variablen (oder einem Feld, einem Array-Element oder einem anderen Speicherort) eines generischen Typs gespeichert sein, für den eine Einschränkung gilt IBar .

Ein Speicherort eines Klassentyps oder eines Schnittstellentyps enthält entweder einen Verweis auf ein Heap-Objekt oder null . Ein Speicherort eines Grundwerttyps enthält eine Sammlung von Bits, die seinen Wert darstellen. Ein Speicherort eines nicht-primitiven Werttyps enthält die verketteten Inhalte aller seiner öffentlichen und privaten Instanzfelder. Ein Speicherort eines generischen Typs T enthält eine Heap-Referenz, wenn T ein Klassentyp oder Schnittstellentyp ist, eine Auflistung von Bits, die einen primitiven Wert darstellen, wenn T ein primitiver Werttyp ist, oder die verketteten Werte von a T s Felder, wenn T ein Strukturtyp ist; Diese Bestimmung basiert auf dem tatsächlichen Typ von T und nicht auf irgendwelchen Einschränkungen.

Wenn Sie zu den Typen Foo und IBar zurückkehren, bewirkt das Speichern von Foo in IBar , dass das System ein neues Heap-Objekt erstellt, das den verketteten Inhalt aller öffentlichen und privaten Felder von% co_de enthält % und speichert einen Verweis auf dieses Heap-Objekt in Foo . Dieses Heap-Objekt verhält sich dann wie jedes andere Heap-Objekt und nicht wie ein wertmäßiger Speicherort. Dinge, die sich manchmal wie Wertetypen und manchmal wie Klassentypen verhalten, können verwirrend sein; Es ist am besten, wenn möglich eine solche gemischte Semantik zu vermeiden.

Die Hauptzeit kann sich für eine Struktur zur Implementierung einer Schnittstelle lohnen, wenn die Verwendung dem zweiten obigen Muster folgt. Zum Beispiel könnte man eine Methode haben:

%Vor%

Wenn in diesem Fall IBar aufgerufen würde, könnte das System die Methode CountUniqueThings(4, 6, 6) direkt auf den übergebenen Parametern vom Typ IEquatable<System.Int32>.Equals(System.Int32) aufrufen. Wenn die Methode stattdessen deklariert wurde:

%Vor%

Dann müsste der Aufrufer ein neues Heap-Objekt erstellen, das den System.Int32 -Wert 4 enthält, eine Sekunde, um den Wert 6 zu halten, eine dritte, die auch den Wert 6 enthalten würde, und müsste dann Verweise an diese übergeben Objekte an die Methode Int32 . Icky.

Die Erstellung von Heap-Objekten hat bestimmte Kosten. Wenn man etwas zu einem Werttyp macht, vermeidet man die Notwendigkeit, Heap-Objekte zu erzeugen, die die große Mehrheit der Instanzen enthalten, was ein großer Gewinn sein kann. Wenn jede erstellte Instanz die Erstellung eines Heap-Objekts zur Aufnahme einer Kopie erforderlich machen würde (z. B. zur Zuweisung an eine Variable vom Typ Schnittstelle), würde der Vorteil vom Werttyp vollständig verschwinden. Wenn Instanzen im Durchschnitt die Erstellung von mehr als einem Heap-Objekt zum Speichern von Kopien erfordern (jedes Mal, wenn ein Typ aus dem Heap-Typ in den Werttyp und zurück konvertiert wird, ist eine neue Instanz erforderlich), kann die Verwendung von Werttypen wesentlich geringer sein effizienter als einfach eine klassenähnliche Instanz zu erstellen, zu der Code eine Referenz übergeben könnte.

    
supercat 30.05.2013 20:05
quelle

Tags und Links