2009-03-06 3 views
1

Ich weiß, dass Box ein beliebtes Konzept mit vielen Informationen über sie, aber ich habe ein paar Fragen, die ich nicht wirklich Antworten finden können:Fragen zu Box

1) Wenn Box auf einen Wert führen type (struct) wird in ein Objekt (Referenztyp) oder Referenztyp konvertiert, warum sollte dann ein Werttyp verwendet werden, der eingerahmt wird und zu einer Leistungseinbuße führt? Ich bin mir der Vorteile und der Eignung in bestimmten Fällen einer Struktur oder einer Klasse bewusst. Es wird gesagt (1), dass Werte (Werttypen) dazu tendieren, auf dem Stapel in einem temporären Speicherplatz zu leben, aber wie lange? Wenn ich den Typ nicht brauche, wie kann ich sicherstellen, dass er in diesem Moment gepflegt und entsorgt wird? Oder kommt das Einwegmuster ins Spiel? Ich nehme an, dass der Grund, eine Struktur zu verwenden, wegen seiner Vorteile sein wird.

Interessanterweise, wenn ich eine Struktur verwenden, um zwei Zeichenfolgen und ein DateTime-Feld zu speichern, wird die Struktur zwei Referenzen (Zeichenfolgen) und die DateTime zusammenhalten. Ich gehe natürlich davon aus, dass dies schneller ist als die verstreuten Werte. Gibt es etwas, auf das ich in diesem Design achten muss? (2).

1) http://en.csharp-online.net/Classes, Structs, and Objects—Boxing and Unboxing

2) http://dotnetperls.com/Content/Struct-Examples.aspx

Ich habe für die Antworten auf hier eine Suche getan, was ich nach bin, aber kein Glück. Normalerweise suche ich auf dieser Seite nach Themen wie GC, Generika, Ausnahmebehandlung usw., da es viel Wissen zum Lernen und Teilen gibt.

Danke für die (potentielle) Bildung an alle Poster! Bitte entschuldigen Sie jede mögliche Naivität. Das Erlernen der Interna bringt mich dazu, einige Zeit damit zu verbringen, IL usw. zu verstehen (etwas, das ich bald angehen werde).

Antwort

4

Wenn Sie den Werttyp niemals in eine Referenzvariable übergeben, wird das Boxing nicht ausgeführt. Wenn Sie nicht wissen, dann beantworten Sie die folgenden questions:

  • Act wie primitive Typen.
  • Haben Sie eine Instanzgröße unter 16 Byte.
  • sind unveränderlich.
  • Wert Semantik sind wünschenswert.

Ich auch in der Regel überlegen, was ist die Lebensdauer einer solchen Variablen. Wenn es sich um eine lokale Variable handelt, die in einer Methode verwendet wird, würde ich struct (ansonsten class) verwenden.

+0

Diese nehmen von der.NET-Richtlinien und sind in der Regel gute Fragen, die Sie sich stellen sollten. –

+0

Ich höre immer wieder von Wert Semantik - was wäre eine Zeit so etwas ist erwünscht? – dotnetdev

+0

http://msdn.microsoft.com/en-us/library/aa664472%28VS.71%29.aspx Gespräche über Wert Semantik und wann sie nützlich sind. –

1

Sie sollten Werttypen wegen ihres logischen Vorteils verwenden, nicht der Leistungsgewinne. Da die Werttypen auf dem Stack verwaltet werden, müssen sie nicht an der Garbage Collection teilnehmen. Wenn Sie einen Typ haben, der ständig erstellt und verworfen wird (wie ein int, float, double usw.), können Sie einen guten Boost erhalten, indem Sie diese in Strukturen umwandeln. Die Sache, auf die Sie achten sollten, ist, dass Sie das nur wirklich berücksichtigen sollten, wenn Sie die Struktur auch unveränderlich machen können.

+0

Was ist erforderlich, um eine Struktur unveränderlich zu machen? Habe ich Recht, wenn ich nur eine geringe Sichtbarkeit habe und es nur lesbar mache? – dotnetdev

+0

Wie funktioniert die Entsorgung auch für Werttypen auf dem Stapel? – dotnetdev

+0

Leider gibt es in C# keine Semantik zum Erstellen unveränderlicher Typen. Es muss lediglich sichergestellt werden, dass der Status nach der Erstellung nicht geändert werden kann. –

0

Sie brauchen nicht immer Boxen, und mit Generika gibt es wenig Bedarf dafür.
Der von Werttypen (struct ist ein Werttyp) verwendete Speicher wird als
in Kürze beansprucht, da die Methode endet/zurückkehrt und Sie nicht tun müssen
tun, damit das geschieht.

Werttypen, die als Instanzelemente deklariert wurden, bleiben im Speicher, bis das Objekt
vom GC gelöscht wird.

Referenztypen werden auf dem verwalteten Heap gespeichert.
Referenztypen, die in einer Methode instanziiert werden, werden vom Garbage Collector gelöscht, wenn kein Objekt einen Verweis darauf enthält.

GC funktioniert von selbst und in den meisten Fällen sollten Sie es in Ruhe lassen.
Sie können nicht vorhersagen, wann ein Objekt vom GC gelöscht wird.

Das Dispose-Muster wird für Referenztypen verwendet, erzwingt jedoch nicht, dass GC ein Objekt löscht. Es wird normalerweise verwendet, um nicht verwaltete Ressourcen freizugeben.

Für Werte im Stapel ist folgendes zu beachten:
Angenommen, Sie haben ein einfaches Programm mit drei Methoden haben, wie unten:
Wenn dieses Programm ausgeführt wird, wird das Hauptverfahren laufen, und so weiter. Bitte beachten Sie die
Zahlen unter:

 

Main 
{ 
    // (0) Stack is empty 
    int firstInt = 0; 
    // (1) Stack now contains: 
    //      firstInt 
    DoSomething1(); 
    // (7) Stack still contains: 
    //      firstInt 
} 
// Program ends 

DoSomething() 
{ 
    int anInteger = 0; 
    // (2) Stack now contains: 
    //     anInteger 
    //     firstInt 
    DoMore() 
    // (5) Stack now contains: 
    //      anInteger 
    //      firstInt 
} 
// (6) anInteger goes out of scope 

DoMore 
{ 
    int anotherInteger = 1; 
    // (3) Stack now contains: 
    //      anotherInteger 
    //      anInteger 
    //      firstInt 
} 
// (4) anotherInteger goes out of scope 

1

Ein paar andere Dinge zu beachten -

Zuerst Sie sicher structs unveränderlich sind (im Allgemeinen) machen wollen. Aus diesem Grund ist es eine gute Faustregel, keine Strukturen zu haben, die Referenztypen enthalten. Strings können eine Ausnahme sein, da sie in C# unveränderlich sind, aber im Hinblick auf eine allgemeine Faustregel für Design, würde ich vorsichtig sein.

Zweitens gibt es einen anderen Anwendungsfall für Strukturen, der bisher nicht erwähnt wurde - große Anzahl kleiner Objekte. Wenn Sie eine große Liste oder ein Array mit kleinen Objekten haben, bieten Strukturen eine wesentlich bessere Cache-Kohärenz und sind absolut kritisch. Dies ist der Grund, warum die meisten 3D-Engines Strukturen für Punkte/Vektoren verwenden - sie neigen dazu, große Punktarrays für Scheitelpunkte usw. zu haben.

Dies ist etwas wert, wenn die Leistung ein wichtiger Teil Ihrer Anwendung ist. In einer meiner Apps wurde beispielsweise durch die Änderung eines einzelnen Typs von einer Klasse in eine Struktur ein langer Prozess (> 5 Minuten Laufzeit) um 40% reduziert. Wenn die Objekte im Speicher nahe beieinander liegen, wenn Sie sie wiederholt in umfangreichen mathematischen Berechnungen verwenden, kann dies enorme Vorteile bringen.

Jetzt - in Ihrem Fall, 2 Strings und eine DateTime wahrscheinlich wird keine Verbesserungen davon sehen. Die Art von Routinen, die auf Strings funktionieren würde, wird wahrscheinlich keine (hoffentlich) schwere Berechnung durchführen, dh: eine halbe Million Punkte im Raum transformieren, oder eine große Matrixlösung machen usw.

Endlich - Sie werden das bemerken .net3.5sp1 machte Strukturen viel nützlicher. Vor 3.5sp1 (auf x86) gab es kein Inlining von Methoden mit Strukturaufrufen. Dies begrenzte die durch Strukturen möglichen Leistungssteigerungen. Wenn Sie Ihr Framework aktualisieren, kann alter Strukturcode sehr viel schneller (in bestimmten Fällen) werden.

+0

Wenn ich mir anschaue, welche Typen Werte sind und welche Referenzen sind, dann würde eine Struktur eine Auswahl von wenigen Werttypen und die ganze Arbeit mit Referenztypen in Klassen funktionieren. Also Referenztypen (Bar String) sind unveränderlich? – dotnetdev

+0

Grundsätzlich, aber andersherum - Referenztypen sind normalerweise veränderbare Typen - dh: Eigenschaften ändern ihre Werte (setzen). Strukturen dagegen wären unveränderlich. Sobald eine Struktur erstellt wurde, möchten Sie, dass sie sich nie ändert. Wenn Sie einen neuen Wert wünschen, erstellen Sie eine neue Struktur. –