Nicht nehmen Sie die Adresse, Holen Sie sich die Größe, oder deklarieren Sie einen Zeiger auf einen verwalteten Typ
Ich habe ein gutes Stück der Forschung, aber bin nun fest, warum bin ich noch immer diesen Fehler. Ich habe ein struct mit folgenden Attributen:
struct Account
{
//private attributes
private double mBalance;
private int mAccountNumber;
private string mName;
private string mDateCreated;
}
und versuche Folgendes zu tun:
class BankManager
{
//private attributes
private unsafe Account *mAccounts;
private unsafe bool *mAccountsAvailable;
private int mNumberAccounts;
}
Sogar nach dem einschalten meiner Klasse Konto um eine Struktur mit "unsicher" für die Attribute in der Klasse BankManager, und zu sagen, der compiler es verwenden kann, unsicheren code (im Eigenschaften -> Build), ich bin noch immer dieser Fehler bei
*mAccounts
Irgendwelche Ideen, warum? Ich bin mir ziemlich sicher, dass alle die Typen, die ich verwende in der struct sind legal, haben Pointer in c#. Vielen Dank im Voraus!
- Warum willst du Zeiger verwenden? Es sieht aus wie
BankManager
habenCollection
vonAccount
s. - Dies kann helfen: stackoverflow.com/questions/2559384/...
- HINWEIS: für jeden, der will, zu betrachten Sie die Adressen stellen Sie sicher, Sie verstehen, was Los ist unter der Haube, BITTE sehen Sie sich diese zwei videos statt das Hirn zermartern auf dieser. (VIDEO 1: youtube.com/watch?v=h6aXzd1nTXQ ) (VIDEO-2: youtube.com/watch?v=mvieNUe9Urs ). Dies gab mir alles was ich wissen wollte. Ich kam aus einer C++ - hintergrund wurde unglaublich frustriert, wenn ich konnte nicht frei Blick auf die Speicher-Adresse mit dem watch-Fenster. Bei der Diskussion über Erinnerung, es ist so nützlich, um eine visuelle Verständnis über das, was da im hintergrund.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Fäden in der Konto-Klasse, die dieses problem verursachen. Um zu verstehen, warum, müssen Sie verstehen, wie der garbage collector funktioniert. Es entdeckt Müll durch die Verfolgung von Referenzen auf Objekte. Der mName und mDateCreated sind solche Hinweise. Die mBalance und mAccountNumber sind nicht, die Felder sind value-Typen. Und, am wichtigsten, die BankManager.mAccounts Feld nicht, es ist ein Zeiger.
Damit der compiler kann sagen, bis vor, dass der garbage collector nie in der Lage sein zu sehen, die string-Referenzen. Weil der einzige Weg, dies zu tun ist, gehen durch die mAccount Feld und nicht einen Verweis.
Die einzige Heilung dafür ist, sich selbst zu begrenzen strikt an Wert-Typen. Der einzige Weg, das zu tun, dass für strings reservieren ist Sie in unmanaged Speicher mit, sagen wir, Marschall.StringToCoTaskMemUni() und speichern die von IntPtr in das Feld ein. Es ist jetzt außerhalb der Reichweite von der garbage collector und können nicht verschoben werden, indem Sie es. Sie haben jetzt auch die Last loslassen, dass der string.
Klar, dass ist nicht praktikabel und anfällig für Undichtigkeiten verursachen, die Art von problem, das so Häufig in C-Programmen. Nicht sicher, warum Sie sind, verfolgen Sie dabei aber bitte beachten Sie, dass eine Referenz auf ein Objekt ist bereits einen einfachen Zeiger, so dass Sie nicht gewinnen nichts durch die Verwendung von Zeigern selbst.
Strings sind Referenztypen in .NETZ und sind nicht für blitvorgänge geeignet für struct-Zeigern. Sehen Für blitvorgänge geeignet und Nicht für blitvorgänge geeignet ist Arten für eine Liste von Wert-Typen für das, was Sie tun möchten.
Es sei denn, Sie haben spezielle Anforderungen, Sie sollten stick mit dem verwalteten Speicher für die Wartbarkeit und die Allgemeine Vernunft.
Verwenden
private unsafe fixed char mName[126];
Strings sind verwaltete Typen, und so sind nicht-Feste arrays.
Sind Sie falsch über die struct enthält Typen, die haben Zeiger, da eine
string
ist eine Art verwaltet, die nicht über einen Zeiger Referenz.Verwalteten Daten bleibt nicht an einem festen Ort, wie das kopieren Sammler kann Dinge bewegen. Dies gilt auch für managed-boxed value types. Geschafft ohne Verpackung Wert-Typen können nur live auf dem stack oder in andere Objekte. Sie haben nur Feste Standorte, wenn Sie in den stack.
Um einen heap-reservierte Struktur, die eine Feste Position von der aus Sie können einen Zeiger, die weiterhin gültig ist, müssen Sie ordnen es in unmanaged Speicher. Jedoch, sobald Sie es zuweisen, die in nicht verwaltetem Speicher, Sie können nicht verwaltete Zeiger in ihm nicht mehr (aka, Sie können nicht string), weil der garbage collector nicht wissen, über diese Pointer, damit es nicht zu aktualisieren, wenn es sich bewegt verwaltete Objekte während der Verdichtung.
Dies ist beispielsweise eine gültige (wenn auch nicht unbedingt guten) Sache zu tun:
Wir hier zugewiesen haben, die Struktur in den nicht verwalteten Speicher. Dies ermöglicht es uns, halten einen Zeiger darauf-wir wissen nicht ändern oder verschieben. Müssen wir manuell frei die Struktur, wenn wir fertig sind mit ihm. Die gleichen manuellen alloc/free und marshalling müsste getan werden, um mAccounts->mName, da es wie eine nicht verwaltete char* (c-style-string).
Machte ich die struct gepackt haben sequential layout zu machen das Verhalten von diesem code näher an C-Pendant, da der code wie oben würde normalerweise nur verwendet werden, wenn dabei interop mit einem nativen C DllImport entrypoint, der erwartet, dass eine bestimmte Struktur layout.