2009-02-24 8 views
39

Sollten Sie Zeiger in Ihrem C# -Code verwenden? Was sind die Vorteile? Wird es von The Man (Microsoft) empfohlen?Sollten Sie Zeiger (unsicherer Code) in C# verwenden?

+0

Die Verwendung von Zeigern bezieht sich im Allgemeinen auf p/invoke. Siehe diesen Artikel: http://www.c-sharpcorner.com/UploadFile/pcurnow/usingpointers10022007082330AM/usingpointers.aspx – gsscoder

+0

Wenn Sie unsicheren Code für eine bestimmte Verwendung verwenden, kann es helfen, all das zu behalten Code in einer privaten inneren Klasse, enthalten in einer öffentlichen Klasse, die sicher ist. Ich mag die Idee nicht, dass der Rest der Anwendung mit Zeigern zu tun hat. Alle obskuren Fehler, die auftauchen, können dann auf diese Klassen zurückgeführt werden, anstatt auf eine unbekannte Stelle im Rest der Anwendung. Es hält die zusätzliche Komplexität davon ab, in den Rest der Codebasis zu gelangen. – Nuzzolilo

Antwort

35

Von "The Man" selbst:

Die Verwendung von Zeigern selten in C# erforderlich ist, aber es gibt einige Situationen, die sie benötigen.Als Beispiele einen unsicheren Zusammenhang mit Zeigern zu ermöglichen, durch den folgenden Fällen gerechtfertigt ist:

  • mit bestehenden Strukturen auf dem Datenträger Umgang
  • Advanced COM oder Platform Invoke Szenarien, die Strukturen mit Zeigern in ihnen beinhalten
  • Erfolgs- kritischer Code

Die Verwendung von unsicherem Kontext in anderen Situationen wird abgeraten.

Insbesondere sollte ein unsicherer Kontext nicht verwendet werden, um zu versuchen, C-Code in C# zu schreiben.

Vorsicht:

-Code geschrieben einen unsicheren Kontext verwendet, kann nicht als sicher überprüft werden, so wird es nur dann ausgeführt werden, wenn der Code vollständig vertrauenswürdig ist. Mit anderen Worten, unsicherer Code kann nicht in einer nicht vertrauenswürdigen Umgebung ausgeführt werden. Beispielsweise können Sie unsicheren Code nicht direkt aus dem Internet ausführen.

Reference

+1

Normalerweise, wenn ich in Beispielen im Internet unsicheren C# -Code sehe, ist es ein Code-Geruch. Das heißt, jemand hat versucht, C-Code in C# zu schreiben. Zu diesem Zeitpunkt ist der Namespace "Managed.Interop" sehr umfangreich, und Sie können ein IntPtr-Objekt in eine Einzelinstanzstruktur einbetten. Daher ist "unsafe" für CLR-Experten für leistungsabhängigen Code gedacht. Es ist keine Möglichkeit, alte Tricks mit Zeigern in der verwalteten Welt am Leben zu erhalten. –

11

Ich kann mich nicht erinnern, dass ich es jemals tun musste - aber ich habe nicht viel Interop gemacht. Das ist die gängigste Anwendung, glaube ich: Aufruf in nativen Code. Es gibt sehr wenige Zeiten, in denen die Verwendung von Zeigern es Ihnen ermöglicht, etwas Code zu optimieren, aber es ist ziemlich selten in meiner Erfahrung.

Wenn es ein Leitfaden ist, betrachte ich mich selbst als ziemlich erfahren in C#, aber wenn ich irgendeinen unsicheren Code machen müsste, müsste ich die Spezifikation/Bücher/MSDN konsultieren, um mich zu führen. Natürlich gibt es viele Leute, die mit unsicheren Code zufrieden sind, aber weniger mit (sagen) Abfrageausdrücken ...

+6

Ich mache eine Menge Bildbearbeitung und LockBits hat mir dort sehr viel Mühe erspart. Ich habe noch nie irgendwo anderen Code verwendet. –

+0

Ich habe es manchmal benutzt, aber selten sogar mit Interop. Wir haben 16 Bit TWAIN eingepackt und mussten nur IntPtr nicht unsafe Code verwenden. Der einzige Ort, an den ich gedacht habe, war die Bitmap-Manipulation, damit ich den Speicher pinnen konnte. –

+1

Die einzige Zeit, die ich jemals benutzt habe, ist auch für die Bildbearbeitung. Ich musste einen bestimmten Teil des Bildes invertieren, und ohne unsafe Code hatte eine merkliche Verzögerung, aber mit dem unsicheren Code wurde es in <1 ms getan. –

2

Sie sollten sie verwenden, wenn Sie sie brauchen; Meistens wird dies bei schwierigen Interop-Szenarien der Fall sein (zum Beispiel wenn ich einen verwalteten Wrapper für DPAPI in .NET 1.0 geschrieben habe), aber sehr gelegentlich könnte es sein, die Performance (nach dem Profiling) zu verbessern, indem man stackalloc oder ähnliches benutzt.

Es wird von Microsoft in so viel empfohlen, wie sie die Designer von C# sind, und sie haben die Entscheidung getroffen, die Möglichkeit hinzuzufügen, unsafe Code darin zu schreiben. Aus der Wahl des Schlüsselworts und der Anforderung, die Methoden/Klassen, in denen Sie es schreiben, mit dem Schlüsselwort zu beschreiben, können Sie sehen, dass es nicht als de-facto Implementierungswahl gedacht ist.

1

natürlich ist es nicht "empfohlen", deshalb ist es mit "unsicher" gekennzeichnet. Aber lass dich nicht davon abschrecken. Trotzdem sollte es Sie zweimal auf Ihren Code schauen lassen. Vielleicht gibt es einen Weg, es zu tun?

3

Unsafe code ist eine vollständig unterstützte Funktion der .NET CLR. Die Vorteile sind Leistung und Kompatibilität mit Binärcode. Die Laufzeit ist eine Sandbox, die verhindert, dass Sie abstürzen und brennen, aber das kostet Sie. In Situationen, in denen Sie extrem intensive Operationen gegen große Blobs im Speicher ausführen, z. B. bei der Bildbearbeitung, ist es schneller, die normale Sicherheit, die die Laufzeit bietet, zu verlassen.

Das gesagt worden ist, denke ich am meisten Leute würden hier sagen "tun Sie es nicht". Die überwiegende Mehrheit der .NET-Entwickler wird bei ihren normalen Aktivitäten nicht auf einen Fall stoßen, der nur durch die Verwendung von unsicherem Code gelöst werden kann.

19

Wenn Sie müssen.

Angenommen, Sie müssen ein großes Graustufenbild, sagen wir 2000x2000 Pixel, falsch darstellen. Schreiben Sie zuerst die "sichere" Version mit GetPixel() und SetPixel(). Wenn das klappt, dann mach weiter. Wenn sich herausstellt, dass es zu langsam ist, müssen Sie möglicherweise die tatsächlichen Bits, aus denen das Bild besteht, ermitteln (vergessen Sie zum Beispiel die Farbmatrizen). Es gibt nichts Schlimmes an der Verwendung von unsicherem Code, aber es erhöht die Komplexität des Projekts und sollte daher nur bei Bedarf verwendet werden.

+0

Beachten Sie, dass der Umgang mit Bildern wahrscheinlich die häufigste Verwendung von unsicheren Code ist, um eine Leistungssteigerung zu erzielen. Ich würde jedoch argumentieren, dass Sie "LockBits" nur verwenden sollten, bevor Sie zu "unsicheren" und "LockBits", also einem mittleren Schritt, gehen. – TheLethalCoder

+0

@TheLethalCoder: eh, vielleicht, wenn Sie keine Erfahrung haben. Sobald Sie die Arbeit erledigt haben, bevor Sie wissen, ob es benötigt wird oder nicht.Es ist keine vorzeitige Optimierung. –

+1

Ich könnte mehr nicht zustimmen. Erwägen Sie, ein Bild von einer Plattform in eine andere zu konvertieren, die jeweils unterschiedliche Klassen und Formate zur Darstellung von Bildern verwenden. Sie können entweder ein Array kopieren, über es zum Konvertieren iterieren, es dann in das Ziel kopieren oder ... Sie können Zeiger zum Kopieren und Konvertieren in einem Durchgang von Quelle zu Ziel verwenden. Der "sichere" Weg ist grob ineffizient, wenn Sie wissen, was Sie tun. – Daniel

3

Ich habe unsicheren Code verwendet, um den Identitätswechsel zu verwenden, um den Dienstzugriff auf Netzwerkfreigaben zuzulassen. Es ist kein Problem, wenn Sie wissen, was Sie tun.

1

Unsafe Code ist die benenfits des .Net Framework wie zu vergessen, habe ich sie einmal geschaffen altmodischen Strukturen wie Stacks und Sachen, aber das war nur für die Schule, heute ich haben die Notwendigkeit zu benutze sie.

1

Tun Sie es, wenn es Ihren Code kürzer und klarer macht.

"Folgen Sie Ihren Neigungen mit Rücksicht auf den Polizisten um die Ecke." WSM

+0

Was haben Zeiger damit zu tun, sich zu wiederholen ...? –

+0

würde nicht werfen einen unsicheren Codeblock in eine ansonsten sichere .NET-Anwendung machen es weniger sauber? Ich denke, Sie könnten C/C++ verwechseln, viele Leute, die von dort kommen, missbilligen viel Code, weil sie denken, dass es langsamer ist. Es war in früheren Versionen, aber es ist heutzutage viel schneller und zuverlässiger als sogar nativer Code, besonders auf Linux-Systemen, wo es fast keinen Bloat gibt. Tatsächlich laufen meine .NET-Anwendungen in Linux schneller als meine C++ - Apps. – osirisgothra

2

Reinterpretive wie Guss nicht von BitConverter geliefert.
Konversion von einem Unint in ein int für Hash-Funktionen, wo Sie nur die Bits interessiert.

Verwenden Sie einige nützliche, gut begründete über C oder C++ idiomatische Funktionen auf Strukturen, wo Sie sie als ein Byte * einer bekannten Länge behandeln müssen, wiederum am nützlichsten für Hashing.

Extrem schnelle binäre Serialisierung von (sehr spezifischen) in Speicherstrukturen (indem man es zu einem Array von ihnen macht), aber um ehrlich zu sein, ist dies besser, indem man einfach auf C++/CLI fällt.

Es muss gesagt werden, dass in vielen Fällen die Aufgabe, die Zeiger benötigt, oft besser gelöst werden kann, indem Sie es in C++/CLI tun und dann dieses in Ihr C# -Projekt als DLL importieren. Es ändert sich nicht, ob der Code "sicher" ist oder nicht, aber er macht eine Reihe von nützlichen Funktionen zum Arbeiten mit zeigerbasierten Strukturen zugänglicher. Es erlaubt Ihnen auch, sich mit generischen Typen oder enums zu beschäftigen, wenn Sie das wirklich wollen.

Die Wahrscheinlichkeit, dass die meisten Entwickler dies tun müssen, ist in der Tat weit entfernt. Nützlich, wenn Sie es brauchen ... obwohl

5

Ich würde die wichtigsten Fragen sagen, sind: -

  • Unsafe Code nicht überprüfbar ist. Dies bedeutet, dass der Code nur von einem Benutzer aus einem vollständig vertrauenswürdigen Kontext ausgeführt werden kann, also wenn Sie jemals einen Benutzer benötigen, um den Code von weniger als vollständig vertrauenswürdig auszuführen (z. B. eine Netzwerkfreigabe nicht konfiguriert), Sie bin geschraubt.
  • Mangel an Überprüfbarkeit (hm nicht sicher, ob das tatsächlich ein Wort ist) bedeutet auch, dass Sie könnten potenziell Messspeicher in Ihrem Programm versauen. Sie sind potenziell bringt ganze Klassen von Fehlern zurück in Ihre Anwendung - Pufferüberläufe, baumelnde Zeiger, Yada Yada Yuck Yuck. ganz zu schweigen davon, dass es möglich ist, Datenstrukturen im Speicher zu beschädigen, ohne zu merken, wenn der Zeiger merkwürdig wird.
  • Wenn Sie möchten, dass Ihr unsicherer Code auf verwaltete Objekte zugreift, müssen Sie sie "anheften". Dies bedeutet, dass der GC das Objekt nicht im Speicher verschieben darf und der verwaltete Heap daher fragmentiert werden kann. Dies hat Auswirkungen auf die Leistung. Daher ist es immer wichtig zu bestimmen, ob eine mögliche Verbesserung nicht durch dieses Problem aufgewogen wird.
  • Ihr Code wird für Programmierer schwieriger, die nicht an den unmanaged Ansatz gewöhnt sind. Sie könnten dann eher dazu neigen, ihren Fuß mit einigen der 'Freiheit', die unsichere Codes geben, abzuschießen.
  • Sie können un-typsicheren Code schreiben; das beseitigt den Vorteil einer warmen, unscharfen Sprache. Jetzt können Sie auf schreckliche Sicherheitsprobleme stoßen. Warum diesen Schritt rückwärts machen?
  • Es macht Ihren Code hässlicher.

Ich bin sicher, dass es mehr gibt, die der Liste hinzugefügt werden könnten; im Allgemeinen, wie andere gesagt haben - vermeiden, es sei denn, du musst z. Aufruf einer unmanaged Methode über p/invoke, die ein spezielles Pointer-Feature benötigt. Selbst dann wird der Marshaller meistens die Notwendigkeit dafür größtenteils verhindern.

'Der Mann' auch sagen zu vermeiden, wenn notwendig, im Grunde.

Oh, schöner Artikel über Pinning here on MSDN übrigens.

+0

Denken Sie daran, dass der Verifier normalerweise (unter voller Vertrauenswürdigkeit) deaktiviert ist, was bedeutet, dass Ihre "Sicherheit" wirklich davon abhängt, dass der Compiler seine Aufgabe korrekt erledigt. Grundsätzlich können Sie IL erstellen, die unsichere Aktionen ausführt –