2015-11-25 10 views
23

Ich bin heute auf eine Methode gestoßen. Ich spreche über: Array.Initialize().Array.Initialize - Warum existiert diese Methode?

Nach der Dokumentation:

This method is designed to help compilers support value-type arrays; most users do not need this method.

Wie wirkt sich das Verfahren zur Herstellung der Compiler Unterstützung Werttypen verantwortlich ist? Soweit ich diese Methode besorgt bin einfach:

Initializes every element of the value-type Array by calling the default constructor of the value type.

auch, warum ist es öffentlichen? Ich sehe mich nicht mit der Notwendigkeit, diese Methode aufzurufen, Compiler initialisieren bereits Arrays, wenn sie erstellt werden, daher ist das manuelle Aufrufen dieser Methode redundant und nutzlos.

Selbst wenn meine Absicht wäre, die Werte eines Arrays zurückzusetzen, würde ich es immer noch nicht nennen, ich würde ein neues erstellen. array = new int[].

So scheint es, dass diese Methode nur für den Compiler existiert. Warum ist das? Kann mir jemand mehr Details geben?

+0

Und wenn Sie die Werte zurücksetzen wollten, ohne ein neues Array zu erstellen, sollten Sie stattdessen auch 'Array.Clear()' verwenden. –

+8

Stimmen schließen? Das scheint mir eine berechtigte Frage zu sein. Vielleicht haben Sie nur gewählt, um basierend auf Titel zu schließen? Ich weiß, warum diese Methode existiert, ist eine Art schwierig, aber wenn Sie alle Fragen lesen, bin ich mir ziemlich sicher, dass Sie mir zustimmen werden. –

+1

@ SonerGönül "Warum wurde das Framework so entworfen?" Ist eine Frage an die Leute, die es entworfen haben, kann antworten. Jeder andere wird nur raten. Die Frage ist nicht für SO geeignet; Wenn Sie wissen möchten, warum Microsoft .NET so entworfen hat, fragen Sie * sie *. – Servy

Antwort

11

Es ist erwähnenswert, dass die Regeln von .NET sich von den Regeln von C# unterscheiden.

Es gibt Dinge, die wir in .NET tun können, die wir in C# nicht tun können, entweder weil der Code nicht verifizierbar ist (ref Rückgabetypen zum Beispiel) oder weil sie Verwirrung stiften könnten.

In C# struct s kann nicht einen definierten parameterlosen Konstruktor haben, und new SomeValueType() Werke Aufruf durch einen Null gefüllten Teil des Speichers zu schaffen (alle Felder daher 0 für numerische Typen, null für Referenztypen zu sein, und das Ergebnis dieser gleichen Regel wieder für andere Werttypen).

In .NET können Sie einen parameterlosen Konstruktor für einen Werttyp haben.

Es ist wahrscheinlich eine schlechte Idee, dies zu tun. Zum einen sind die Regeln darüber, wann genau es aufgerufen wird und wann genau der Wert Null ist, und was bei der Zuweisung in verschiedenen Fällen passiert, nicht ganz einfach (zB new SomeValueType() wird es aber new T() in einer generischen Methode nennen, wo T ist SomeValueType wird nicht!). Das Leben ist einfacher, wenn das Ergebnis von new SomeValueType() immer nullfüllend ist. Das hat zweifellos das Design von C# beeinflusst, dies aber nicht zuzulassen, obwohl .NET dies tut.

Aus diesem Grund wird Array.Initialize() nie sinnvoll für neue Arrays eines beliebigen Typs, der in C# geschrieben wurde, da das Aufrufen des Konstruktors und das Zero-Filling dasselbe ist.

Aus demselben Grund ist es auch möglich, dass ein Typ in einer anderen .NET-Sprache geschrieben wird (zumindest in CIL), die einen parameterlosen Konstruktor hat, der tatsächlich wirkt. Aus diesem Grund ist es möglich, dass ein Compiler für eine solche Sprache sein Äquivalent zu new SomeValueType[3] haben möchte, um diesen Konstruktor für alle Typen im Array aufzurufen. Und deshalb ist es sinnvoll, eine Methode im Rahmen zu haben, die eine solche Füllung ermöglicht, damit ein Compiler für eine solche Sprache davon Gebrauch machen kann.

Also, why is it public?

So kann es durch Code aufgerufen werden durch einen solchen hypothetischen Konstruktor erzeugt auch in einem Kontext, in dem Sicherheitseinschränkungen es verhindern, dass private Methoden einer anderen Baugruppe aufrufen.

+1

"Sie können dies jetzt mit C# 6 tun": Nein, das geht nicht. Diese Funktion wurde in Betracht gezogen, und IIRC wurde sogar in einer der Vorabversionen implementiert, aber sie wurde schließlich zurückgezogen. In der endgültigen Version, erhalten Sie diesen Fehler: 'CS0568 Structs kann keine expliziten parameterlosen Konstruktoren enthalten ' –

+1

@ThomasLevesque ah, danke, Sie können mir sagen, dass ich noch nicht wirklich mit der neuesten Version gespielt habe! Auch gut! Die Vagueren parameterloser Konstruktoren auf Werttypen würden sich wahrscheinlich nicht lohnen. –

1

Für mich selbst sieht es aus wie die Initialize() -Methode durch das Array läuft und erstellt die Werttypen innerhalb. So mit einem neuen Array Sie ein neues leeres Array erhalten und so erhalten Sie mit Array.Clear(), aber mit Array.Initialize() Sie bekommen ein Array voller frischer erstellt Werttypen (Typen und Länge basierend auf dem alten Array).

Und das sollte der ganze Unterschied sein.

+0

Angenommen ich habe 'int [] a = new int [3] {7, 9, 13,}; 'in C#. Deine Antwort könnte so gelesen werden, dass wenn ich 'a.Initialize(); 'darauf verwende, dann werde ich ein Array von Nullen (das' default (int) ') danach haben. Dies ist jedoch falsch. Wenn Sie diese Funktion wünschen, verwenden Sie stattdessen 'Array.Clear (a, 0, a.Length);'. –

0

Basierend auf den CLR source durchläuft das Verfahren jeden Index des Arrays und initialisiert den Werttyp auf diesem Index durch den Standard-Konstruktor, ähnlich wie initobj IL Anweisung aufrufe (I fragen, was passiert, wenn der Konstruktor eine Ausnahme auslöst, obwohl) . Die Methode ist öffentlich, weil das direkte Aufrufen einer privaten Methode aus IL es ein wenig verifizierbar machen würde.

Heutige C# -Compiler initialisieren nicht jedes Element des Arrays, wenn Sie es erstellen, einfach setzen Sie jeden Index auf den Standardwert des Typs. C# 6 führt die Implementierung von Standardkonstruktoren für Werttypen ein (die bereits von CLR unterstützt wurden), weshalb dies für Sprachen mit unterschiedlicher Array-Erstellungssemantik erforderlich ist.

0

Sie können die erwartete Verwendung in dem Testcode siehe:

https://github.com/dotnet/coreclr/blob/3015ff7afb4936a1c5c5856daa4e3482e6b390a9/tests/src/CoreMangLib/cti/system/array/arrayinitialize.cs

Grundsätzlich setzt ein Array von nicht-intrinsischer Wert-Typen wieder auf ihren Standardzustand (T).

Es scheint nicht wie ein erstaunlich nützliches Werkzeug, aber ich kann sehen, wie es sinnvoll sein könnte, Arrays von nicht-intrinsischen Wertdaten Null zu setzen.