Laden...

boxing unboxing

Erstellt von BillTuer vor 17 Jahren Letzter Beitrag vor 17 Jahren 3.879 Views
B
BillTuer Themenstarter:in
325 Beiträge seit 2005
vor 17 Jahren
boxing unboxing

[EDIT]Abgeteilt von Objects structs casting boxing unboxing[/EDIT]

Habe auch eine Frage zu diesem Thema:

ich erzeuge eine Struktur a vom Typ A und belege die Struktur-Variable i (int) mit dem Wert 11.


A a = new A();
a.i = 11;

Auf dem Stack liegt jetzt der Wert 11.

Nun erzeuge ich ein Objekt o und packe a dort hinein.

object o = a;

Damit erhalte ich einen Verweis auf dem Stack, der auf eine Kopie von i (11) auf dem Heap zeigt, richtig?

Nun caste ich o auf A und rufe die Struktur-Methode set auf, die i belegt.

((A)o).set(12);

Jetzt findet "Unboxing" statt, oder?
D.h. die Kopie landet auf dem Stack und ist ein eigener Wert...?

Wenn ich nun

((A)o).i

ausgebe, erhalte ich dennoch eine "11"...!?

Wieso? 🙂 Wo ist mein Denkfehler?

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo BillTuer,

beim Boxing wird keine Referenz auf den bestehenden Wert erzeugt, sondern eine auf eine Kopie des Wertes.

Die SDK-/MSDN-Doku schreibt dazu:

Wenn ein Werttyp mittels Boxing konvertiert wird, muss ein völlig neues Objekt reserviert und erstellt werden.

herbivore

B
BillTuer Themenstarter:in
325 Beiträge seit 2005
vor 17 Jahren

Und was passiert mit dieser Kopie des Wertes beim Unboxing? Sie geht doch zurück auf den Stack und wäre damit wieder direkt änderbar, oder?
Verstehe einfach nicht, wieso da 11 steht...

Anders:
Wird o durch den Cast auf A nicht zum Wertetyp und ich kann die Variable i einfach über set() setzen?

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo BillTuer,

die Kopie, die beim Boxing erstellt wird, liegt in Heap, nicht auf dem Stack. Beim Unboxing nur ihr Wert herausgeholt.

herbivore

347 Beiträge seit 2006
vor 17 Jahren

Stell' dir Boxing einfach so vor, dass eine Instanz einer Klasse erzeugt wird, die deinen ValueType als Feld besitzt. Unboxing kannst du dir vorstellen, als wenn der Wert dieses Feldes wieder zurückgegeben wird.
Das ist nicht 100% exakt, aber genau genug um es sich besser vorstellen zu können. 😉
Ein boxed ValueType verhält sich in vielerlei Hinsicht wie ein Referenztyp.

Bleistift:

struct Sample
{
   public int Field;
   public override ToString()
   {
      return Field.ToString();
   }
}

static void Miep(object instance, object value)
{
   FieldInfo fi = instance.GetType().GetField("Field");
   fi.SetValue(instance, value);
}

static void Main()
{
  Sample s = new Sample();
  s.Field = 1;
  object o = s;
  Miep(o, 2);
  Console.WriteLine(o); // ergibt 2!
}
B
BillTuer Themenstarter:in
325 Beiträge seit 2005
vor 17 Jahren

Wenn ein Werttyp mittels Boxing konvertiert wird, muss ein völlig neues Objekt reserviert und erstellt werden.

Ist in meinem Fall damit das o gemeint?

Glaube, ich habe es jetzt verstanden.
Der erste Cast holt den Wert 11 vom Heap in den Stack und der Wert wird im Stack auf 12 gesetzt.
Bei der Ausgabe jedoch wird erneut Unboxing gemacht und damit noch mal der Wert vom Heap geholt (11) und einfach ausgegeben.
Richtig?

49.485 Beiträge seit 2005
vor 17 Jahren

Hallo BillTuer,

Ist in meinem Fall damit das o gemeint?

o enthält eine Referenz auf den geboxten Wert, also auf die Kopie auf dem Heap.

Der erste Cast holt den Wert 11 vom Heap in den Stack und der Wert wird im Stack auf 12 gesetzt.

Nein, der erste Cast holt den Wert 11 vom Stack und erzeugt eine Kopie im Heap. Eine Referenz auf diese Kopie wird in o gespeichert.

Durch den Zugriff (A(o)) wird der Wert aus dem Objekt auf dem Heap geholt (also nochmal kopiert) und durch das .set (12) wird in dieser Kopie der Wert 12 gesetzt. Das Setzen ist also schon völlig witzlos und ändert nur die Kopie der Kopie, die zudem sofort nach dem Setzen nicht mehr erreichbar ist und entfernt wird.

herbivore

B
BillTuer Themenstarter:in
325 Beiträge seit 2005
vor 17 Jahren

Danke, gehe davon aus, dass ich es jetzt verstanden habe.

B
BillTuer Themenstarter:in
325 Beiträge seit 2005
vor 17 Jahren

Habe hier noch was zu diesem Thema:


interface I1
    {
        void set(int ii);
    }
    
    struct A : I1
    {
        public int i;

        public void set(int ii)
        {
            i = ii;
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            A a = new A();

            a.i = 11;
            object o = a;
            ((I1)o).set(12);

            Console.WriteLine(((A)o).i);    // Ausgabe 12
            Console.WriteLine(a.i);         // Ausgabe 11

            Console.ReadLine();
        }
    }

Kann mir jemand erklären, wieso der Cast des Objektes auf I1 in Kombination mit der Methode set den Wert von o verändert?
Ich verstehe es nicht.

D
386 Beiträge seit 2007
vor 17 Jahren

Nicht problemrelevant, aber du wuerdest mir Kopfschmerzen ersparen wenn du etwas an diesen drei Dingen aenderst:

  • I1 als Interfacename

  • i und ii als Variablennamen

  • 11 als Testwert

Je nach Schrift und Aufloesung sieht das arg schlecht lesbar aus.

Pound for pound, plutonium is about as toxic as caffeine when eaten.

O
778 Beiträge seit 2007
vor 17 Jahren

Hinter ((I1)o) könnte sich auch theoretisch ein Verweistypobjekt verstecken, daher wird nicht auf eine Kopie, sondern auf das tatsächliche Objekt zugegriffen.

Alles andere wäre auch Entwicklertechnisch gesehen Blödsinn, weil dann der praktiche Nutzen von Schnittstellen-implementierenden Strukturen gleich Null wäre, und damit das ganze Konzept von Schnittstellen auseinanderbrechen würde, weil du nie weißt, ob du nu mit dem Objekt oder nur mit der Kopie arbeiten würdest, bzw. wenn du's rausgekriegt hast (z.B. über Typvergleich mit ValueType) kannst du dich dann freuen, das du rausgekriegt hast, warum dein Code nicht funktioniert 😁

B
BillTuer Themenstarter:in
325 Beiträge seit 2005
vor 17 Jahren

Das hört sich sehr logisch an, danke! 🙂