Kann die Adresse nicht übernehmen, die Größe von erhalten oder einen Zeiger auf einen verwalteten Typ deklarieren

8

Ich habe ein bisschen Nachforschungen angestellt, stehe aber jetzt fest, warum ich diesen Fehler immer noch bekomme. Ich habe eine Struktur mit folgenden Attributen:

%Vor%

und versuche folgendes zu tun:

%Vor%

Selbst nachdem ich meinen Klassenaccount in eine Struktur umgewandelt habe, "unsicher" für die Attribute in der Klasse BankManager verwendet habe und dem Compiler mitteilen kann, dass er unsicheren Code verwenden kann (in Eigenschaften - & gt; Build), erhalte ich immer noch diesen Fehler

%Vor%

Irgendwelche Ideen, warum? Ich bin ziemlich sicher, dass alle Typen, die ich in der Struktur verwende, legal sind, Zeiger in c # zu haben. Vielen Dank im Voraus!

    
SantasNotReal 08.11.2012, 22:41
quelle

5 Antworten

20

Die Zeichenfolgen in der Account-Klasse verursachen dieses Problem. Um zu verstehen, warum, müssen Sie verstehen, wie der Garbage Collector funktioniert. Es entdeckt Müll, indem Verweise auf Objekte verfolgt werden. Die mName und mDateCreated sind solche Referenzen. Die Werte mBalance und mAccountNumber sind nicht , diese Felder sind Werttypen. Und am wichtigsten ist das Feld BankManager.mAccounts nicht, es ist ein Zeiger.

So kann der Compiler vorweg sagen, dass der Garbage Collector nie die String-Referenzen sehen kann. Weil der einzige Weg dies zu tun ist, durch das Feld mAccount zu gehen, und es ist keine Referenz.

Das einzige Heilmittel dafür ist, sich streng auf Werttypen zu beschränken. Die einzige Möglichkeit, dies für Zeichenketten zu tun, besteht darin, sie in nicht verwaltetem Speicher beispielsweise mit Marshal.StringToCoTaskMemUni () zuzuweisen und das IntPtr in dem Feld zu speichern. Es ist jetzt außerhalb der Reichweite des Müllsammlers und kann nicht von ihm bewegt werden. Sie werden nun auch die Last haben, diese Zeichenfolge freizugeben.

Natürlich ist das nicht praktisch und anfällig für Lecks, ein Problem, das in C-Programmen so häufig vorkommt. Nicht sicher, warum Sie dies überhaupt verfolgen, aber bedenken Sie, dass ein Verweis auf ein Objekt bereits ein einfacher Zeiger ist, so dass Sie nichts gewinnen, indem Sie Zeiger selbst verwenden.

    
Hans Passant 09.11.2012, 00:44
quelle
3

Strings sind Referenztypen in .NET und sind für Strukturzeiger nicht blitbar. Unter Blitable und Nicht-Blitable-Typen finden Sie eine Liste von Werttypen, die Sie ausführen möchten.

Sofern Sie keine besonderen geschäftlichen Anforderungen haben, sollten Sie bei der Verwaltung und der allgemeinen Vernunft für verwaltete Speicher sorgen.

    
hyru 08.11.2012 22:57
quelle
1

Verwenden Sie private unsafe fixed char mName[126];
Zeichenfolgen sind verwaltete Typen, also nicht fixierte Arrays.

    
avishayp 08.11.2012 22:52
quelle
0

Sie liegen falsch bezüglich der Struktur, die Typen enthält, die Zeiger haben können, weil string ein verwalteter Typ ist, der keine Zeigerreferenz haben kann.

    
Xint0 08.11.2012 22:50
quelle
-1

Verwaltete Daten bleiben nicht an einem festen Ort, da der Kopiersammler Dinge verschieben kann. Dies gilt gleichermaßen für verwaltete Boxed-Value-Typen. Verwaltete nicht verpackte Werttypen können nur auf dem Stapel oder in anderen Objekten leben. Sie haben nur feste Positionen, wenn sie sich im Stapel befinden.

Um eine Heap-allokierte Struktur zu erstellen, die einen festen Ort hat, von dem Sie einen Zeiger nehmen können, der weiterhin gültig ist, müssen Sie ihn in unmanaged Speicher zuordnen. Wie auch immer , sobald Sie es im nicht verwalteten Speicher zuordnen, können Sie keine verwalteten Zeiger mehr einfügen (aka, können Sie nicht verwenden Zeichenfolge), weil der Garbage Collector nicht über diese Zeiger so wissen Es aktualisiert sie nicht, wenn es verwaltete Objekte während der Komprimierung bewegt.

Dies ist zum Beispiel eine gültige (aber nicht unbedingt gute) Aufgabe:

%Vor%

Hier haben wir die Struktur im nicht verwalteten Speicher zugewiesen. Dies ermöglicht uns, einen Zeiger darauf zu halten, von dem wir wissen, dass er sich nicht ändert oder bewegt. Wir müssen die Struktur manuell freigeben, wenn wir damit fertig sind. Das selbe manuelle Alloc / Free und Marshalling müsste an mAccounts- & gt; mName vorgenommen werden, da es sich um ein nicht verwaltetes char * (C-style String) handelt.

Ich habe die Struktur sequenzielles Layout gepackt, um das Verhalten dieses Codes seinem C-Gegenstück näher zu bringen, weil Code wie oben normalerweise nur verwendet wird, wenn Interop mit einem nativen C DllImport-Eingabepunkt durchgeführt wird, der ein bestimmtes Strukturlayout erwartet .

    
David Jeske 21.08.2013 18:03
quelle

Tags und Links