Heim  >  Artikel  >  Backend-Entwicklung  >  Kompilierung von C#-Grundkenntnissen Grundkenntnisse (18) Ein- und Auspacken von Werttypen (1)

Kompilierung von C#-Grundkenntnissen Grundkenntnisse (18) Ein- und Auspacken von Werttypen (1)

黄舟
黄舟Original
2017-02-11 13:49:431306Durchsuche

Es ist tatsächlich sehr interessant, mehr über das Ein- und Auspacken zu erfahren. Schauen wir uns zunächst an, warum es zum Ein- und Auspacken kommt.
Sehen Sie sich den folgenden Code an:

    class Program
    {
        static void Main(string[] args)
        {
            ArrayList array = new ArrayList();

            Point p;//分配一个

            for (int i = 0; i < 5; i++)
            {
                p.x = i;//初始化值

                p.y = i;

                array.Add(p);//装箱
            }
        }
    }

    public struct Point
    {
        public Int32 x;

        public Int32 y;
    }

Führen Sie eine 5-malige Schleife durch, initialisieren Sie jedes Mal ein Feld vom Typ „Punktwert“ und platzieren Sie es dann in der ArrayList. Struct ist eine Struktur vom Typ Wert. Was wird also in ArrayList gespeichert? Schauen wir uns noch einmal die Add-Methode von ArrayList an. Sie können die Add-Methode in MSDN sehen:
public virtual int Add(Object value),
Sie können sehen, dass der Parameter von Add vom Typ Object ist, d. h. der erforderliche Parameter ist ein Verweis auf ein Objekt . Das heißt, die Parameter müssen hier Referenztypen sein. Was ein Referenztyp ist, muss nicht näher erläutert werden. Es handelt sich lediglich um eine Referenz auf ein Objekt auf dem Heap. Zum besseren Verständnis sprechen wir jedoch noch einmal über Heap und Stack.
1. Stapelbereich (Stapel) – wird vom Compiler automatisch zugewiesen und freigegeben und speichert Funktionsparameterwerte, lokale Variablenwerte usw.
2. Heap-Bereich (Heap) – vom Programmierer zugewiesen und freigegeben. Wenn der Programmierer ihn nicht freigibt, kann er vom Betriebssystem recycelt werden, wenn das Programm endet.
Zum Beispiel:

    class Program
    {
        static void Main(string[] args)
        {
            Int32 n;//这是值类型,存放在栈中,Int32初始值为0
            
            A a;//此时在栈中开辟了空间

            a = new A();//真正实例化后的一个对象则保存在堆中。
        }
    }

    public class A
    {
        public A() { }
    }

Zurück zur obigen Frage: Die Add-Methode erfordert Referenztypparameter. Was soll ich tun? Dann müssen Sie Boxen verwenden. Das sogenannte Boxen besteht darin, einen Werttyp in einen Referenztyp umzuwandeln. Der Konvertierungsprozess ist wie folgt:
1. Weisen Sie Speicher im verwalteten Heap zu. Die zugewiesene Speichermenge ist die Speichermenge, die von den einzelnen Feldern des Werttyps benötigt wird, plus die Speichermenge, die von zwei zusätzlichen Mitgliedern (dem Typobjektzeiger und dem synchronisierten Blockindex) benötigt wird, über die alle Objekte im verwalteten Heap verfügen.
2. Kopieren Sie das Werttypfeld in den neu zugewiesenen Speicher.
3. Geben Sie die Adresse des Objekts zurück. Zu diesem Zeitpunkt handelt es sich bei der Adresse um einen Verweis auf ein Objekt, und der Werttyp wurde nun in einen Referenztyp konvertiert.
Auf diese Weise wird in der Add-Methode ein Verweis auf ein eingerahmtes Point-Objekt gespeichert. Das verpackte Objekt bleibt im Heap, bis der Programmierer es verarbeitet oder der Systemmüll es einsammelt. Zu diesem Zeitpunkt überschreitet die Lebensdauer des geschachtelten Werttyps die Lebensdauer des ungeschachtelten Werttyps.
Mit dem obigen Boxen ist es natürlich, es zu entpacken. Wenn Sie das 0. Element des Arrays herausnehmen möchten:
Punkt p = (Punkt)array[0];
Was Sie tun müssen Hier wird abgerufen: Die Referenz des Elements 0 der ArrayList wird in den Punktwerttyp p eingefügt. Um dieses Ziel zu erreichen, muss zunächst die Adresse jedes Point-Felds des Box-Point-Objekts ermittelt werden. Das war’s zum Auspacken. Die in diesen Feldern enthaltenen Werte werden dann vom Heap in die stapelbasierte Werttypinstanz kopiert. Beim Unboxing handelt es sich im Wesentlichen um den Prozess, einen Verweis auf einen primitiven Werttyp zu erhalten, der in einem Objekt enthalten ist. Tatsächlich verweist die Referenz auf den nicht verpackten Teil der verpackten Instanz. Daher ist es beim Unboxing im Gegensatz zum Boxen nicht erforderlich, Bytes in den Speicher zu kopieren. Aber es gibt noch einen weiteren Punkt: Ein Feldkopiervorgang erfolgt unmittelbar nach dem Auspacken.
Daher wirkt sich das Ein- und Auspacken negativ auf die Geschwindigkeit und den Speicherverbrauch des Programms aus. Achten Sie daher darauf, wann das Programm automatisch Ein-/Auspackvorgänge ausführt, und versuchen Sie, diese Situationen beim Schreiben von Code zu vermeiden.
Achten Sie beim Unboxing auf die folgenden Ausnahmen:
1. Wenn die Variable, die „einen Verweis auf die geboxte Werttypinstanz“ enthält, null ist, wird eine NullReferenceException geworfen.
2. Wenn das Objekt, auf das die Referenz zeigt, keine Boxed-Instanz des erwarteten Werttyps ist, wird eine InvalidCastException ausgelöst.
Zum Beispiel das folgende Code-Snippet:

             Int32 x = 5;

            Object o = x;

            Int16 r = (Int16)o;//抛出InvalidCastException异常

Weil es beim Unboxing nur in den ursprünglichen Unboxed-Werttyp konvertiert werden kann. Ändern Sie den obigen Code wie folgt:

             Int32 x = 5;

            Object o = x;

            //Int16 r = (Int16)o;//抛出InvalidCastException异常

            Int16 r = (Int16)(Int32)o;

Das ist richtig.
Nach dem Auspacken erfolgt eine Feldkopie, wie im folgenden Code gezeigt:

            //会发生字段复制
            Point p1;

            p1.x = 1;

            p1.y = 2;

            Object o = p1;//装箱,发生复制

            p1 = (Point)o;//拆箱,并将字段从已装箱的实例复制到栈中

Sehen Sie sich das folgende Codesegment an:

            //要改变已装箱的值

            Point p2;

            p2.x = 10;

            p2.y = 20;

            Object o = p2;//装箱

            p2 = (Point)o;//拆箱

            p2.x = 40;//改变栈中变量的值

            o = p2;//再一次装箱,o引用新的已装箱实例

Der Zweck hier ist das Kopieren die Box Der x-Wert von p2 wird auf 40 geändert. Auf diese Weise müssen Sie das Feld einmal entpacken, das Feld einmal in den Stapel kopieren, den Wert des Felds im Stapel ändern und dann das Boxen durchführen Sie müssen eine neue Instanz auf dem Heap erstellen. Daraus erkennen wir auch die Auswirkungen des Einpackens/Auspackens und Kopierens auf die Programmleistung.
Schauen wir uns noch ein paar Code-Schnipsel zum Boxen und Unboxen an:

            //装箱拆箱演示
            Int32 v = 5;

            Object o = v;

            v = 123;

            Console.WriteLine(v + "," + (Int32)o);

Hier finden drei Mal Boxen statt.

            Object o = v;

            v = 123;

Aber in Boxing trat auch in Console.WriteLine auf. Warum? Da es hier in WriteLine String-Typ-Parameter gibt und jeder weiß, dass String ein Referenztyp ist, muss (Int32)o hier eingerahmt werden. Hier wird erneut das Problem der Verwendung des +-Zeichens zum Verbinden von Zeichenfolgen im Programm erläutert. Wenn während der Verbindung mehrere Werttypen vorhanden sind, werden mehrere Boxing-Operationen ausgeführt.
Der obige Code kann jedoch geändert werden:

            //修改后
            Console.WriteLine(v.ToString() + "," + o);

Auf diese Weise gibt es kein Boxen.
Sehen Sie sich den folgenden Code noch einmal an:

 Int32 v = 5;

            Object o = v;

            v = 123;

            Console.WriteLine(v);

            v = (Int32)o;

            Console.WriteLine(v);

Hier kommt nur eine Box vor, d. h. Object o = v hier, und Console.WriteLine ist mit int, bool, double usw. überladen. es findet also kein Boxen statt.

Das Obige ist der Inhalt der Grundkenntnisse von C# Grundkenntnisse (18) Boxing und Unboxing von Werttypen (1) Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php). cn)!


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn