Was macht ToList intern? | Listen kopieren

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 1 Antwort in diesem Thema. Der letzte Beitrag () ist von Haudruferzappeltnoch.

    Was macht ToList intern? | Listen kopieren

    Hallo,

    Vorwort
    ich habe mich danach umgesehen, wie ich am einfachsten eine List(T) mit Zahlen klonen kann, sodass eine Änderung in der zweiten Liste keine Auswirkungen auf die ursprüngliche Liste hat. Dabei stieß ich auf
    ToList().

    In dieser Stackoverflow-Antwort und den beiden Kommentaren steht, dass das man ToList() verwenden kann, solange es sich um primitive Datentypen handelt. Mir ist bewusst, dass man bei Objekten eine tiefgehende Kopie (DeepClone) verwenden müsste, um unabhängige Kopien zu erhalten.

    Anliegen
    Ich habe mich nun interessehalber damit befasst, zu ergründen, was ToList eigentlich intern macht.
    Mein VB.NET-Code erstellt zwei Listen, ListA und ListB. ListB wird durch die Verwendung der ToList()
    -Methode auf ListA erstellt.

    VB.NET-Quellcode

    1. Imports System.Linq
    2. Public Class Form1
    3. Private Sub Button1_Click()
    4. Dim ListA As New System.Collections.Generic.List(Of UInteger) From {1UI, 10UI, 100UI}
    5. Dim ListB As System.Collections.Generic.List(Of UInteger) = ListA.ToList()
    6. End Sub
    7. End Class


    Das ist der dazugehörige IL-Code. Bei Schritt Nr. IL_001c wird Liste B erstellt und mit Werten von A befüllt.
    IL

    Quellcode

    1. .assembly _
    2. {
    3. .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = (
    4. 01 00 08 00 00 00 00 00
    5. )
    6. .custom instance void [System.Runtime]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = (
    7. 01 00 01 00 54 02 16 57 72 61 70 4e 6f 6e 45 78
    8. 63 65 70 74 69 6f 6e 54 68 72 6f 77 73 01
    9. )
    10. .custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = (
    11. 01 00 02 00 00 00 00 00
    12. )
    13. .hash algorithm 0x00008004 // SHA1
    14. .ver 0:0:0:0
    15. }
    16. .class private auto ansi '<Module>'
    17. {
    18. } // end of class <Module>
    19. .class public auto ansi Form1
    20. extends [System.Runtime]System.Object
    21. {
    22. // Methods
    23. .method public specialname rtspecialname
    24. instance void .ctor () cil managed
    25. {
    26. // Method begins at RVA 0x2050
    27. // Code size 7 (0x7)
    28. .maxstack 8
    29. IL_0000: ldarg.0
    30. IL_0001: call instance void [System.Runtime]System.Object::.ctor()
    31. IL_0006: ret
    32. } // end of method Form1::.ctor
    33. .method private
    34. instance void Button1_Click () cil managed
    35. {
    36. // Method begins at RVA 0x2058
    37. // Code size 35 (0x23)
    38. .maxstack 8
    39. IL_0000: newobj instance void class [System.Collections]System.Collections.Generic.List`1<uint32>::.ctor()
    40. IL_0005: dup
    41. IL_0006: ldc.i4.1
    42. IL_0007: callvirt instance void class [System.Collections]System.Collections.Generic.List`1<uint32>::Add(!0)
    43. IL_000c: dup
    44. IL_000d: ldc.i4.s 10
    45. IL_000f: callvirt instance void class [System.Collections]System.Collections.Generic.List`1<uint32>::Add(!0)
    46. IL_0014: dup
    47. IL_0015: ldc.i4.s 100
    48. IL_0017: callvirt instance void class [System.Collections]System.Collections.Generic.List`1<uint32>::Add(!0)
    49. IL_001c: call class [System.Collections]System.Collections.Generic.List`1<!!0> [System.Linq]System.Linq.Enumerable::ToList<uint32>(class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0>)
    50. IL_0021: pop
    51. IL_0022: ret
    52. } // end of method Form1::Button1_Click
    53. } // end of class Form1



    Da ich noch nicht gesehen habe, inwiefern mit Pointern oder mit Kopien gearbeitet wird, habe ich mir den JIT-Asm-Code geben lassen.
    JIT Asm

    Quellcode

    1. ; Core CLR 7.0.1323.51816 on x86
    2. Form1..ctor()
    3. L0000: ret
    4. Form1.Button1_Click()
    5. L0000: push ebp
    6. L0001: mov ebp, esp
    7. L0003: push esi
    8. L0004: mov ecx, 0x103437a8
    9. L0009: call 0x00e4300c
    10. L000e: mov esi, eax
    11. L0010: mov ecx, 0x5d64c10
    12. L0015: mov edx, 0xad6
    13. L001a: call 0x71d500d0
    14. L001f: mov ecx, [0x8a52404]
    15. L0025: lea edx, [esi+4]
    16. L0028: call 0x00e10068
    17. L002d: inc dword ptr [esi+0xc]
    18. L0030: mov edx, [esi+8]
    19. L0033: cmp [ecx+4], edx
    20. L0036: jbe short L0048
    21. L0038: lea eax, [edx+1]
    22. L003b: mov [esi+8], eax
    23. L003e: mov dword ptr [ecx+edx*4+8], 1
    24. L0046: jmp short L0055
    25. L0048: mov ecx, esi
    26. L004a: mov edx, 1
    27. L004f: call dword ptr [0x1b9d5198]
    28. L0055: inc dword ptr [esi+0xc]
    29. L0058: mov ecx, [esi+4]
    30. L005b: mov edx, [esi+8]
    31. L005e: cmp [ecx+4], edx
    32. L0061: jbe short L0073
    33. L0063: lea eax, [edx+1]
    34. L0066: mov [esi+8], eax
    35. L0069: mov dword ptr [ecx+edx*4+8], 0xa
    36. L0071: jmp short L0080
    37. L0073: mov ecx, esi
    38. L0075: mov edx, 0xa
    39. L007a: call dword ptr [0x1b9d5198]
    40. L0080: inc dword ptr [esi+0xc]
    41. L0083: mov ecx, [esi+4]
    42. L0086: mov edx, [esi+8]
    43. L0089: cmp [ecx+4], edx
    44. L008c: jbe short L009e
    45. L008e: lea eax, [edx+1]
    46. L0091: mov [esi+8], eax
    47. L0094: mov dword ptr [ecx+edx*4+8], 0x64
    48. L009c: jmp short L00ab
    49. L009e: mov ecx, esi
    50. L00a0: mov edx, 0x64
    51. L00a5: call dword ptr [0x1b9d5198]
    52. L00ab: mov ecx, 0x103437a8
    53. L00b0: call 0x00e4300c
    54. L00b5: mov ecx, eax
    55. L00b7: mov edx, esi
    56. L00b9: call dword ptr [0x1b9d5030]
    57. L00bf: pop esi
    58. L00c0: pop ebp
    59. L00c1: ret



    Hier habe ich leider keine Erfahrung, und brauche Hilfe. Sehe ich es richtig, dass sich mittels L00b0: call 0x00e4300c die Adresse von A geholt wird und dann Werte rüberkopiert werden, es aber einen Pointer auf 0x1b9d5030 gibt?

    Viele Grüße
    Bartosz
    Mit Maschinencode kenne ich mich nicht aus.
    Aber .ToList kann nicht klonen.
    Primitive Datentypen und Strukturen klonen immer von sich aus. Werttyp heißt sowas. Die werden immer wieder neu erzeugt.
    Klassen und die damit verbundenen Objekte sind Referenztypen. Die werden nur einmal erzeugt, immer irgendwo durch ein New. Danach wird immer nur der Zeiger rumgereicht zu dem Objekt.
    Eine Klon-Funktion muss also selbst eine neue Instanz mit New aufrufen und dann halt die Eigenschaften nachbauen.