Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Boxing und Unboxing in C# (https://www.delphipraxis.net/162513-boxing-und-unboxing-c.html)

-187- 25. Aug 2011 18:56

AW: Heap und Stack - Unterschiede
 
Achso da wird quasi im Hintergrund "geboxt" ? Hmm .. seltsam das Ganze... Aber Anhand deiner Erklärung habe ich folgenden Code aufgestellt. Der Vorteil ist deutlich sichtbar:

Code:
        private void Form1_Load(object sender, EventArgs e)
        {
            int i = 50;
            string s = "50";
            object o = i;
            //object o = s;
            MessageBox.Show(testFunction(o));
        }

        private string testFunction(object o)
        {
            return Convert.ToString(o);
        }
Ich kann über's "Boxing" eine Funktion mit jedem x beliebigen Datentyp aufrufen. Ok, wann und ob ich es brauche wird sich zeigen ...

jfheins 25. Aug 2011 19:01

AW: Heap und Stack - Unterschiede
 
Zitat:

Zitat von SebE (Beitrag 1119673)
Delphi-Quellcode:
int i = 0;
string s = i.ToString();
Ich denke hier wird implizit das Boxing angewandt.
Es geht auch kürzer:
Code:
(5).ToString()

Da der Typ Int32 zum Glück die .toString() Methode überschreibt, wird hier nicht geboxt. Also schlechtes Beispiel ^^

Aber man deklariere sich einen beliebigen struct und siehe da, man kann toString() aufrufen obwohl das gar nicht deklariert wurde ;-)


Zum Beispiel in Java kann man keine generische ArrayList<double> deklarieren, weil die Klasse einen Referenztype haben möchte. Dafür gibt es dann die Wrapperklasse Double (großegeschrieben) ... sowas wollte man sich vll. ersparen.

SebE 25. Aug 2011 19:04

AW: Heap und Stack - Unterschiede
 
Zitat:

Zitat von -187- (Beitrag 1119667)
Zitat:

Zitat von jfheins (Beitrag 1119665)
Eine List<int> und eine List<double> benutzen also die gleiche List<T> wie List<String> oder List<StringBuilder>

Das hab ich nicht verstanden ? :pale:

Wie in deinem kleinen ShowMessage-Beispiel:
Code:
public class List<T> where T: object {
  private T[] values;

  public void Add(T value) { ... }
  ...
  }
Code:
public List<string> myStringList;
public List<int> myIntList;
...

SebE 25. Aug 2011 21:29

AW: Heap und Stack - Unterschiede
 
Zitat:

Zitat von jfheins (Beitrag 1119678)
Da der Typ Int32 zum Glück die .toString() Methode überschreibt, wird hier nicht geboxt. Also schlechtes Beispiel ^^

Aber man deklariere sich einen beliebigen struct und siehe da, man kann toString() aufrufen obwohl das gar nicht deklariert wurde ;-)

Ja, da hast du recht. Auch Int, Bool, ... sind - wie alle Structs - von object abgeleitet (und besitzen u.a. ToString()).

Folgende Ableitungshierachie finde ich irgendwie komisch.
object <-- valueType <-- struct <-- int, wobei object eine Klasse und struct (wie der Name schon sagt) keine ist.
Alles nach valueType (structs, int, ...) liegt auf dem Stack, alle Verweistypen auf dem Heap, wo liegt object?

implementation 25. Aug 2011 21:57

AW: Heap und Stack - Unterschiede
 
Zitat:

Zitat von SebE (Beitrag 1119673)
Ich denke hier wird implizit das Boxing angewandt.
Es geht auch kürzer:
Code:
(5).ToString()

Es geht auch noch kürzer:
Code:
5.ToString()
// ... oder ...
"Hello!".ToUpper()
;)

Und SebE: Ein object ist ein Verweistyp -> Heap.
Die Value-Typen sind nicht wirklich von object abgeleitet, dort kommt nur wieder das Boxing ins Spiel.

jfheins 25. Aug 2011 22:12

AW: Heap und Stack - Unterschiede
 
Zitat:

Zitat von SebE (Beitrag 1119693)
Ja, da hast du recht. Auch Int, Bool, ... sind - wie alle Structs - von object abgeleitet (und besitzen u.a. ToString()).

Folgende Ableitungshierachie finde ich irgendwie komisch.
object <-- valueType <-- struct <-- int, wobei object eine Klasse und struct (wie der Name schon sagt) keine ist.
Alles nach valueType (structs, int, ...) liegt auf dem Stack, alle Verweistypen auf dem Heap, wo liegt object?

object liegt auf dem Heap, wie jeder andere Verweistyp. Falls ein Wert-Typ nach object gecastet wird, wird automatisch ein Objekt erstellt dass den Werttyp beinhaltet.

Das mag am Anfang komisch sein. Aber wenn man darüber Bescheid weiß, ist das halt eine kleine Eigenart die man beachten sollte. In Delphi z.B. ist es nicht ohne weiteres möglich, eine Funktion mit einem Parameter beliebigen Typ zu erstellen. Entweder man überlädt sie x-mal mit TObject, int, long, double, string oder man nimmt einen Variant. Wobei ein Variant mehr Overhead haben dürfte als das boxing.

Btw.: Sooo häufig ist mir das Boxing noch nicht in die Quere gekommen seit ich mit C# einwickle. Eigentlich noch nie. Häufig kann man ja statt structs auch Klassen verwenden, dann hat sich das mit dem Boxing eh erübrigt.

An vielen Stellen wo geboxt wird, wird die nicht geboxte Kopie auch weggeworfen. Zum Beispiel:
Code:
Mein_Eventhandler
{
var abc = new(MyStruct);
abc.Name = NameTxt.Text;
abc.Age = (int)AgeNum.value;
Contactlist.Add(abc);
abc.Haircolor = Color.Green;
}
Jetzt hast du natürlich die Situation dass die Haarfarbe nicht mehr in der Kontaktliste steht. Wenn myStruct eine Klasse wäre, würde es noch übernommen.
Aber der Code sieht ja auch komisch aus. Erst alle Felder befüllen und dann in die Liste rein ;-)

Medium 25. Aug 2011 22:14

AW: Boxing und Unboxing in C#
 
Es ist übrigens sehr wohl möglich, primitive Datentypen als var- oder out-Parameter zu übergeben. AFAIK wird dabei auch nicht im Hintergrund rumgeboxed, sondern lediglich die Zeigernatur (wie auch in Delphi) via Sprachmitteln verborgen. Ebenso ist die Typsicherheit durch den Compiler gewährt. Alles in allem ist das ja eigentlich "nur" konsequentes OOP Durchziehen, so dass - zumindest semantisch - immer alles Objekte sein können.
Ich bin zudem nicht völlig davon überzeugt, dass die Runtime da hinter den Kulissen wirklich in vollem Umfang ein Objekt nach "allen Regeln der Kunst" aufbaut. Ich mutmaße auch dort eine Portion Compiler- bzw. Runtimemagic mehr, damit solche Dinge nicht allzu teuer werden.
Ich war auch zu Beginn von .NET recht skeptisch und hielt das für Humbug, aber man erhält einfach eine Fülle von Freiheiten und Komfort auf diese so einfache Weise, die man wirklich erst merkt, wenn man die 100ste List<float> nicht separat neu ableiten musste :). Und der Preis ist doch eher marginal. Ich habs argwöhnisch erwartet, und lieben gelernt.

Elvis 25. Aug 2011 22:47

AW: Heap und Stack - Unterschiede
 
Zitat:

Zitat von implementation (Beitrag 1119699)
Die Value-Typen sind nicht wirklich von object abgeleitet, dort kommt nur wieder das Boxing ins Spiel.

Doch sind sie, allerdings haben sie eine Identitätskrise.
Zum einen sollen sie sich wie Werte auf dem Stack verhalten, also Artefakte, die nur du ihre tatsächlichen Werte bestimmt sind und die dann auch eine Garbage Collection brauchen.
Aber andererseits, erwartet man von ihnen, dass sie zuweisungskompatibel zu Object oder gar Interfaces sind, und dabei sogar PolyMorphie unterstützen sollen (ToString, Equals, GetHashCode).
Gerade Interfaces sind eine kleine pöhse Falle. Man erwartet es als Anfänger nicht, aber dass hier boxt auch:
Code:
interface ITöröö

  void Abc();
}

struct EinStruct

  public void Abc(){}
}
....
ITöröö xyz = new EinStruct();
Das CLR-Team hat hier einen ganz guten Job gemacht. Denn wenn man ValueTypes als solche benutzt, verhalten sie sich auch so.
Mit allen daraus resultierenden Optimierungen oder auch Performance-Fallen.
Aber andererseits brechen sie .Nets "rooted type system" nicht. Also dass alle Typen auf eine Wurzel zurückgehen.
Wenn man es denn wirklich braucht, kann man sie in eine Referenz stecken, die ein Interface oder vom Typ Object ist.
In dem Moment kann man es auch verschmerzen, dass der ValueType verpackt wird. Denn ohne diesen Mechanismus würde man á la Java nicht weiterkommen.
Eine Box ist hierbei vergleichbar mit einer Klasse, die ein Feld vom Typen deines ValueTypes hat und die gleichen Methoden und Properties hat.
Code:
class PseudoBox : ITöröö
{
   private EinStruct DerWert;
   
  public void Abc()
  {
    DerWert.Abc();
  }
}
Solch eine Box ist übrigens vergleichbar mit den Value classes aus Java. Also Integer anstatt int.
Was die CLR aber für uns tut ist, dass all das transparent passiert. Wir sehen die Box nicht. Wenn wir uns xyz per Reflection anschauen, sehen wir alles aus EinStruct, was da auch hingehört.
ValueTypes und Boxing sind also Taschenspielertricks der CLR um performante native Typen wie Int32 oder Double verwenden zu können, die aber im Typsystem keine komische Ausnahme spielen, sondern sich genauso einfügen, wie alle selbstdefinierten Typen.

Was passiert, wenn man kein Boxing in der Runtime hat sieht man "schön" an Delphi oder Java, denn dort sind native Typen etwas komplett anderes als alle anderen selbst definierbaren Typen.
In Java, kann man native Typen nichtmal für Generics nutzen, in Delphi gibt es Record helpers, aber keinerlei Möglichkeit zum Beispiel Integer oder TDateTime mit Helpers zu erweitern. Wobei letzteres nicht unbedingt einen technischen Grund haben muss. Ich denke da war einfach der Anspruch bei Borlemb nicht hoch genug.

Elvis 25. Aug 2011 22:55

AW: Boxing und Unboxing in C#
 
Zitat:

Zitat von Medium (Beitrag 1119704)
Es ist übrigens sehr wohl möglich, primitive Datentypen als var- oder out-Parameter zu übergeben. AFAIK wird dabei auch nicht im Hintergrund rumgeboxed, sondern lediglich die Zeigernatur (wie auch in Delphi) via Sprachmitteln verborgen.

ref parameter sind tatsächlich Zeiger. Aber das macht die CLR nur mit Parametern. (Weshalb man zum Beispiel keine ref-Parameter für Iteratoren nutzen kann. Denn dort landen diese ja als Felder, und Felder dürfen keine Referenzen sein.


Zitat:

Ich bin zudem nicht völlig davon überzeugt, dass die Runtime da hinter den Kulissen wirklich in vollem Umfang ein Objekt nach "allen Regeln der Kunst" aufbaut. Ich mutmaße auch dort eine Portion Compiler- bzw. Runtimemagic mehr, damit solche Dinge nicht allzu teuer werden.
Natürlich ist eine Box keine eigene Klasse, das wäre ja kaum zu verschleiern und dadurch nicht transparent. Außerdem braucht die Box keine eigenen Metadaten oder Implementierungen der Methoden und spart damit auch einen Batzen an Verwaltung.
Aber der Aufwand der Instanzierung einer Box ist gleichzusetzen mit dem einer Klasse, welche dein Struct als Feld hat. Zaubern kann das CLR Team ja auch nicht. Und sie werden richtige Klassen wohl kaum langsamer instanzieren lassen, nur damit Boxes relativ schneller sind. ;-)

Medium 26. Aug 2011 00:04

AW: Boxing und Unboxing in C#
 
Hm, leuchtet irgendwie ein :) Hätte mir da nur ggf. sowas vorstellen können, wie es z.B. bei Copy-on-Write gemacht wird: Semantisch wird es wie ein Objekt ausgesehen lassen, intern aber so lange als nativer Typ verwaltet, bis man tatsächlich nicht mehr anders kann. So Sachen wie eben "12.ToString()" ließen sich ja umschiffen, ohne da wirklich etwas zu instanziren. Wenn man mal davon absieht, dass die Methode ja eh wie schon erwähnt etwas anders implementiert ist.
Danke dir für die Details!


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:15 Uhr.
Seite 2 von 3     12 3      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz