array - Wann sollten Zeiger in C#/. NET verwendet werden?



c# pointer to object (4)

Ich weiß, dass C # dem Programmierer die Möglichkeit gibt, auf Zeiger in einem unsicheren Kontext zuzugreifen. Aber wann ist das nötig?

Unter welchen Umständen wird die Verwendung von Zeigern unvermeidlich?

Ist es nur aus Leistungsgründen?

Warum stellt C # diese Funktionalität auch in einem unsicheren Kontext zur Verfügung und entfernt alle verwalteten Vorteile daraus? Ist es möglich, Verwendungszeiger zu verwenden, ohne theoretisch die Vorteile einer verwalteten Umgebung zu verlieren?

https://ffff65535.com


Wann ist das nötig? Unter welchen Umständen wird die Verwendung von Zeigern unvermeidlich?

Wenn die Nettokosten einer verwalteten, sicheren Lösung inakzeptabel sind, sind die Nettokosten einer unsicheren Lösung akzeptabel. Sie können die Nettokosten oder den Nettonutzen ermitteln, indem Sie den Gesamtnutzen von den Gesamtkosten subtrahieren. Die Vorteile einer unsicheren Lösung sind Dinge wie "keine Zeit verschwendet für unnötige Laufzeitprüfungen, um die Korrektheit zu gewährleisten"; Die Kosten sind (1) Code zu schreiben, der sicher ist, selbst wenn das verwaltete Sicherheitssystem ausgeschaltet ist, und (2) sich damit befassen müssen, den Garbage Collector möglicherweise weniger effizient zu machen, weil er sich nicht durch Speicher bewegen kann, in den ein nicht verwalteter Pointer läuft es.

Oder, wenn Sie die Marshalling-Ebene schreiben.

Ist es nur aus Leistungsgründen?

Es scheint pervers, Zeiger in einer verwalteten Sprache aus anderen Gründen als der Leistung zu verwenden.

Sie können die Methoden in der Marshalklasse verwenden, um in den allermeisten Fällen mit dem Interagieren mit nicht verwaltetem Code zu arbeiten. (Es kann einige Fälle geben, in denen es schwierig oder unmöglich ist, das Marshalling-Getriebe zu verwenden, um ein Interop-Problem zu lösen, aber ich kenne keine.)

Natürlich, wie gesagt, wenn Sie die Marshal-Klasse schreiben, dann können Sie natürlich nicht die Marshalling-Ebene benutzen , um Ihr Problem zu lösen. In diesem Fall müssen Sie es mithilfe von Zeigern implementieren.

Warum stellt C # diese Funktionalität in einem unsicheren Kontext zur Verfügung und entfernt alle verwalteten Vorteile daraus?

Diese verwalteten Vorteile sind mit Leistungskosten verbunden. Wenn Sie z. B. ein Array nach seinem zehnten Element fragen, muss die Laufzeitumgebung prüfen, ob ein zehnten Element vorhanden ist, und eine Ausnahme auslösen, wenn dies nicht der Fall ist. Mit Zeigern werden Laufzeitkosten eliminiert.

Die entsprechenden Entwicklerkosten sind, dass wenn Sie es falsch machen, Sie mit Speicherbeschädigungsfehlern fertig werden, die Ihre Festplatte formatieren und Ihren Prozess eine Stunde später abstürzen, anstatt sich mit einer netten, sauberen Ausnahme zum Zeitpunkt des Fehlers zu beschäftigen.

Ist es möglich, Zeiger zu verwenden, ohne theoretisch die Vorteile einer verwalteten Umgebung zu verlieren?

Unter "Vorteilen" vermute ich, dass Sie Vorteile wie Müllabfuhr, Typensicherheit und referentielle Integrität meinen. Daher lautet Ihre Frage im Wesentlichen: "Ist es theoretisch möglich, das Sicherheitssystem abzuschalten, aber trotzdem die Vorteile des eingeschalteten Sicherheitssystems zu nutzen?" Nein, klar ist es nicht. Wenn Sie dieses Sicherheitssystem ausschalten, weil Sie nicht mögen, wie teuer es ist, dann erhalten Sie nicht die Vorteile davon, an zu sein!


Angenommen, Sie möchten zwischen zwei Anwendungen über IPC (Shared Memory) kommunizieren, dann können Sie die Daten in den Speicher übertragen und diesen Datenzeiger per Windows-Messaging oder etwas anderem an die andere Anwendung übergeben. Bei der empfangenden Anwendung können Sie Daten zurückholen.

Nützlich auch im Falle der Übertragung von Daten von .NET zu Legacy-VB6-Anwendungen, in denen Sie die Daten in den Arbeitsspeicher marshallen, übergeben Zeiger auf VB6 App mit Win msging, VB6 copymemory () verwenden, um Daten aus dem verwalteten Speicherplatz in VB6 Apps nicht verwalteten Speicher abzurufen Raum..


Die häufigsten Gründe, Pointer explizit in C # zu verwenden:

  • Low-Level-Arbeit (wie String-Manipulation), die sehr leistungsabhängig ist,
  • Schnittstelle zu nicht verwalteten APIs.

Der Grund, warum die mit Pointern verknüpfte Syntax aus C # entfernt wurde (nach meinem Wissen und Standpunkt - Jon Skeet würde besser B- antworten), war in den meisten Situationen überflüssig.

Aus der Perspektive des Sprachdesigns müssen Sie, sobald Sie Speicher durch einen Garbage-Collector verwalten, strenge Einschränkungen einführen, was mit Pointern möglich ist und was nicht. Wenn Sie beispielsweise einen Zeiger verwenden, der in die Mitte eines Objekts zeigt, kann dies schwerwiegende Probleme für den GC verursachen. Sobald die Einschränkungen vorhanden sind, können Sie die zusätzliche Syntax einfach weglassen und mit "automatischen" Referenzen enden.

Auch der in C / C ++ gefundene äußerst wohlwollende Ansatz ist eine häufige Fehlerquelle. Für die meisten Situationen, in denen Mikro-Performance keine Rolle spielt, ist es besser, strengere Regeln zu verwenden und den Entwickler zugunsten weniger Bugs einzuschränken, die sehr schwer zu entdecken wären. Für gängige Geschäftsanwendungen sind daher die so genannten "verwalteten" Umgebungen wie .NET und Java besser geeignet als Sprachen, die vermutlich gegen die Bare-Metal-Maschine arbeiten.


Zeiger sind ein inhärenter Widerspruch zur verwalteten, von Müll gesammelten Umgebung.
Sobald Sie anfangen, mit rohen Zeigern zu spielen, hat der GC keine Ahnung, was vor sich geht.

Insbesondere kann es nicht feststellen, ob Objekte erreichbar sind, da es nicht weiß, wo sich die Zeiger befinden.
Es kann auch keine Objekte im Speicher verschieben, da dies Ihre Zeiger zerstören würde.

All dies würde durch GC-verfolgte Zeiger gelöst werden; Das sind Referenzen.

Sie sollten Zeiger nur in unordentlichen fortgeschrittenen Interop-Szenarien oder für hochentwickelte Optimierung verwenden.
Wenn du fragen musst, solltest du es wahrscheinlich nicht tun.





unsafe