2014-08-27 6 views
17

Soweit ich weiß, int.TryParse(string, out int) existiert seit Framework 2.0. So auch int?.Warum gibt T.TryParse keine Nullable zurück <T>

Gibt es einen Grund einen out Parameter zu verwenden, anstatt ein int? mit HasValue Satz true von false auf der Fähigkeit abhängig Rückkehr zu konvertieren?

+3

Das wäre eine Frage für das .NET Framework-Entwicklerteam. Die meisten Läden schreiben eine Erweiterungs-Methode 'string', die etwas in der Form von' ToNullableInt' heißt und das gewünschte Verhalten implementiert. Ich wäre nicht überrascht, wenn eine zukünftige Version von C# dies nativ unterstützt. –

+0

Vielleicht, weil andere Sprachen keine so einfache Syntax für Nullables haben. Z.B. In C++/CLI müssen Sie 'Nullable result = int :: TryParse (...)' schreiben. – Stephan

+0

Welchen Grund haben Sie, um irgendeine zufällige Zeichenkette als 'null' zu behandeln? Die meisten möglichen Verwendungen, die ich bei einer Umwandlung von "string" in "int?" Gesehen habe, sind die Umwandlung einer leeren Zeichenfolge in "null", die Konvertierung einer nicht leeren Zeichenfolge in ein gültiges 'int' und die Ablehnung von zufälligen Fehlern wie' @ ($^V @ Q (% ^% (@ B^N ('.) Dies wäre bereits eine gute Wahl für' int.TryParse', unabhängig von seinem Rückgabetyp. Können Sie ein vernünftiges Szenario angeben, in dem 'TryParse '' T? 'zurückgeben ist eigentlich wünschenswert? – hvd

Antwort

21

Ich kann nicht über die tatsächlichen Gründe sagen, aber ich sehe drei mögliche Gründe:

1) Nullable types wurden seit .NET 2.0, während die first TryParse methods waren bereits rund 1,1 .NET eingeführt.Wenn NULL-Typen eingeführt wurden, war es für eine solche API-Änderung zu spät. und neue Klassen implementieren TryParse nicht anders, weil das Muster bereits festgelegt wurde.

2) Nicht alle Typen können mit dem Nullable structure verwendet werden, nur Werttypen können. Es gibt jedoch Methoden, die dem Muster Try* folgen und Referenztypen zurückgeben müssen. Zum Beispiel kann ein Wörterbuch absolut legitim null als ein Element enthalten, daher benötigt seine TryGetValue method eine zusätzliche Möglichkeit auszudrücken, dass ein Schlüssel nicht gefunden wurde.

3) Die Art und Weise die Try* -Methoden geschrieben werden, ist es möglich, Code wie folgt zu schreiben:

int myValue; 
if (int.TryParse("42", out myValue)) { 
    // do something with myValue 
} 
    // do something else 
} 

nun vorstellen, wenn TryParse nur eine int? zurückgegeben. Sie können entweder der myValue Variable verfügen und das Ergebnis verlieren:

if (int.TryParse("42").HasValue) { 
    // do something with ... what? You didn't store the conversion result! 
} 
    // do something else 
} 

Oder Sie können ein Nullable-Variable hinzufügen:

int? myValue = int.TryParse("42"); 
if (myValue.HasValue) { 
    // do something with myValue.Value 
} 
    // do something else 
} 

Das ist kein Vorteil gegenüber der aktuellen Version mehr vorhanden, und stattdessen es erfordert schreiben myValue.Value in einigen späteren Instanzen, wo sonst eine einfache value würde ausreichen würde. Beachten Sie, dass Sie in vielen Fällen nur die Information benötigen, ob der Vorgang für die if-Anweisung erfolgreich war.

+0

1) Ich wusste nicht, dass' TryParse' Methoden in Framework 1.0 existieren. 2) Daran habe ich nicht gedacht. 3) Die Anzahl der Zeilen ist kein Problem. Es ist nur so, dass ich das out-Schlüsselwort ein wenig ... unnatürlich finde, um es in C# zu verwenden. – krimog

+0

@Krimog: Entschuldigung, ich korrigiere 1.0 zu 1.1, da ich jetzt kein 1.0 Beispiel finden konnte (aber die Schlussfolgerung der Aussage ist offensichtlich dieselbe). –

+2

@Krimog Warum sollte ein Sprachschlüsselwort "unnatürlich" sein? – asawyer

3

Als Gründe wir nur vermuten können, aber einige mögliche Gründe sind:

Zuordnung Overhead: eine Box Wert eingeht, ein in Art gebaut einige (kleine) Performance-Overhead über.

keine echten Gewinne:

int res; 
if int.TryParse("one", out res) { 
    //something 
} 

ist nicht viel schlechter als

int? res = int.TryParse("one"); 
if (res.HasValue){ 
    int realres = res.Value 
    //something 
} 
+5

Dies ist nicht "boxed"; zumindest nicht in der üblichen Bedeutung von Boxen in .NET; ein "int?" benötigt 8 Bytes auf dem Stack; ein 'int' und ein' bool': benötigen 8 Bytes auf dem Stack ... aber: ein 'bool' und ein' ref int' könnten tatsächlich * 12 Bytes * auf dem Stack (in x64) belegen; p Bedeutung: der Die "out" -Version erfordert tatsächlich mehr Zuweisung, plus natürlich einige zusätzliche De-Referenz-Operationen, die in der anderen nicht notwendig sind. Mein Punkt: Beide haben Kosten. –

+0

@MarcGravell: Ist der Wert nicht "out" Box? – krimog

+1

@krimog nein, tut es nicht; Es übergibt einfach die Adresse des Feldes/local - das kann eine Adresse auf dem Stapel sein. Es erstellt explizit keine Box. –

5

Hier ist ein Zitat von Julie Lerman Blog (Back von 2004):

ich gespielt habe mit nullable in den März-Vorschau-Bits, aber noch nicht im Mai und enttäuscht von der aktuellen (aber geplant für eine ernsthafte Verbesserung durch die bcl team !!!) Leistung, wenn ich die Verwendung nullable<t> über aktuelle Optionen verglichen. So zum Beispiel mit Werttypen:

Vergleich myNullableInt.HasValue zu (in VB) ist myInt < 0

oder mit Referenztypen

myNullableThing.HasValue Vergleich zu „if not myThing=null

die Nullable Type ist derzeit viel viel langsamer. Ich bin von ein paar auf dem BCL-Team versprochen, dass der Plan ist, die Nullable viel leistungsfähiger machen.

Ich habe auch den Hinweis, dass in der Zukunft gegeben worden ist, folgendes möglich sein wird:

Nullable<T> Parse(string value); 
Nullable<Int32> i = Int32.Parse(some String); 

Und wird mehr performant als TryParse. Das wird auch interessant sein.

ich annehmen, dass wie immer, der Nutzen überwiegt die Kosten.

Wie dem auch sei, in der kommenden C# vNext, können Sie tun:

DateTime.TryParse(s, out var parsedDateTime); 

Drehen TryParse in einem Einzeiler.

+2

Sie können jetzt sogar einen Einzeiler verwenden, wenn Sie kein Nullwert benötigen: 'DateTime dt = DateTime.TryParse (s, out dt)? dt: DateTime.MinValue; ' –

+0

@TimSchmelter Du hast Recht, aber ein ziemlich langer Liner :) –

21

Der einfache Grund ist, weil, wenn int.TryParse der Sprache hinzugefügt wurde, Nullable<T> nicht existierte.

In this blog post by Eric Lippert gibt es eine Linie in Richtung der Unterseite, die lautet:

Die Lösung ist Ihre eigene Erweiterungsmethode Version von TryParse zu schreiben, wie es geschrieben worden wäre, es auf NULL festlegbare Werttypen in der gewesen Der erste Platz

was deutlich macht, dass NULL-fähige Typen nicht zur Verwendung in der ursprünglichen Implementierung von TryParse verfügbar waren. Eric Lippert war in dem Team, das den C# -Compiler geschrieben hat, also würde ich sagen, dass das eine ziemlich autoritative Quelle ist.

+1

Danke, dass du dir die Zeit genommen hast, das zu finden;) – krimog

+4

Erneut trifft die Erik Lippert Fangemeinde von Stackoverflow wieder auf Eric Eric Lippert und seine sofortige Upvotes. : D –

+2

Wer * sonst * kann Fragen beantworten, auch wenn er keine Fragen beantwortet? – Magus

4

Ein weiterer möglicher Grund:

Generics für .NET und C# in ihrer derzeitigen Form fast nicht geschehen: Es ist ein sehr enger Anruf ist, und das Merkmal fast nicht den Cut für Whidbey machen (Visual Studio 2005). Funktionen wie das Ausführen von CLR-Code in der Datenbank erhielten eine höhere Priorität.

...

Letztlich wäre ein Löschmodell von Generika angenommen wurde, wie für Java, da wäre das CLR-Team eine das VM-in-Generika-Design ohne externe Hilfe nie verfolgt hat.

Quelle: http://blogs.msdn.com/b/dsyme/archive/2011/03/15/net-c-generics-history-some-photos-from-feb-1999.aspx

Mein Punkt ist: Die Mehrheit der Veränderungen in der BCL (oder zumindest diejenigen, die nicht direkt zu Generika bezogen) wahrscheinlich benötigt sowohl die Arbeit mit und ohne Generika, in Fall, dass das Feature im letzten RTM geschnitten wurde.

Natürlich macht dies auch aus einer aufrufenden Clientperspektive Sinn: alle konsumierenden Sprachen (ok, es waren damals nicht so viele) wären im Idealfall in der Lage gewesen, sie zu benutzen - und out Parameter waren nicht so schneiden -edge als Generika.

Verwandte Themen