2010-03-15 5 views
5

eine Methode mit der folgenden SignaturWie lautet das Standardverhalten für einen out-Parameter, wenn eine TryXxxx-Methode false zurückgibt?

bool TryXxxx(object something, out int toReturn) 

Unter der Annahme, was es für toReturn akzeptabel ist falsch, wenn TryXxxx kehrt zu sein?

In dem es ist, dass toReturn nie verwendet werden sollte, wenn TryXxxx fehlschlägt ist es wichtig?

Wenn toReturn ein nulle Typ war, dann wäre es sinnvoll, null zurückzugeben. Aber int ist nicht nullbar und ich will es nicht zwingen müssen.

Wenn toReturn immer ein bestimmter Wert ist, wenn TryXxxx ausfällt, riskieren wir, die Position zu haben, an der 2 Werte als gleichwertig betrachtet werden können. Ich kann sehen, dass dies zu möglicher möglicher Verwirrung führt, wenn der "Standard" -Wert als eine gültige Antwort zurückgegeben wurde (wenn TryXxxx Wahr zurückgibt).

Von einem Implementierungspunkt, wenn es aussieht, toReturn zu haben, ist ein [ny] Wert am einfachsten, aber gibt es etwas Wichtigeres zu beachten?

Antwort

6

Ich würde ausdrücklich Dokument als den Standardwert für den Typen verwenden (was auch immer diese Art ist, so in diesem Fall 0, aber default(T) in einem allgemeineren Fall). Es gibt verschiedene Fälle, in denen der Standardwert genau dem entspricht, wenn der Wert nicht vorhanden ist. In diesem Fall können Sie den Rückgabewert der Methode einfach ignorieren.

Beachten Sie, dass dies Methoden wie int.TryParse und Dictionary.TryGetValue tun.

+0

Und außerdem, wenn Sie sich um das Ergebnis kümmern genug, dass Sie nicht standardmäßig verwenden möchten, es sei denn, das war explizit der Wert, der XYZ (geparst usw.) war), dann sollten Sie den Rückgabewert der Methode sowieso überprüfen. –

+0

Hatte nicht daran gedacht, dass der Verbraucher einen Grund hat, den zurückgegebenen Wert zu verwenden, wenn Try false zurückgegeben hat. –

4

Es könnte default(int) sein:

bool TryXxxx(object something, out int toReturn) 
{ 
    toReturn = default(int); 
    return false; 
} 
2

ich default sagen würde, aber eigentlich sollte es keine Rolle. Die Konvention mit TryX besagt, dass der Aufrufer den Rückgabewert überprüfen und nur den Parameter out verwenden soll, wenn die Methode true zurückgibt.

2

Grundsätzlich ist es etwas. Ich würde es als "nicht definiert" dokumentieren. Sensible Werte sind:

  • default()
  • MinValue, MaxCValue, NewValue (als neue int()), null
  • NAN-Wert (Double.NaN)

Aber im Allgemeinen, Ich möchte wirklich "nicht definiert" sagen und den Leuten nicht etwas geben, auf das sie sich verlassen können.

+0

Theoretisch können Sie die Methode als "undefiniertes" Verhalten beschreiben, aber in Wirklichkeit müssen Sie eine konkrete Implementierung bereitstellen. Ja, Sie könnten einen zufälligen Wert zurückgeben, um vielleicht schlummernde Bugs zu provozieren, aber eine praktische Lösung ist normalerweise, einen festen Standardwert zurückzugeben, daher ist "Standard (T)" wahrscheinlich der beste Wert. Beachten Sie auch, dass Sie in diesem Fall die Methode weiterhin als undefiniertes Verhalten dokumentieren können, wodurch Sie bei Bedarf die Möglichkeit haben, den Wert später zu ändern. Ich würde jedoch wahrscheinlich einen festen Standard selbst zurückgeben. –

0

1) Eigentlich denke ich, dass es nicht wichtig sein sollte, weil Sie immer das boolesche Ergebnis dieser Methoden überprüfen sollten, bevor Sie den Wert verarbeiten. Dafür gibt es die TryXXX-Methoden.

2) In solchen Fällen beziehe ich mich jedoch immer auf die Implementierung im .NET-Framework, um Konsistenz zu gewährleisten.Und ein kurzer Blick in Reflector zeigt, dass der Int32-Typ liefert 0, wenn Parsing fehlgeschlagen:

internal static unsafe bool TryParseInt32(string s, NumberStyles style, NumberFormatInfo info, out int result) 
{ 
    byte* stackBuffer = stackalloc byte[1 * 0x72]; 
    NumberBuffer number = new NumberBuffer(stackBuffer); 
    result = 0; // <== see here! 
    if (!TryStringToNumber(s, style, ref number, info, false)) 
    { 
     return false; 
    } 
    if ((style & NumberStyles.AllowHexSpecifier) != NumberStyles.None) 
    { 
     if (!HexNumberToInt32(ref number, ref result)) 
     { 
      return false; 
     } 
    } 
    else if (!NumberToInt32(ref number, ref result)) 
    { 
     return false; 
    } 
    return true; 
} 

jedoch nicht die Details der Implementierung zu wissen, könnte es immer noch passieren, dass das Parsen Problem tritt auf, wenn bereits ein Wert zugewiesen wurde (teilweise). In diesem Fall ist der Wert möglicherweise nicht mehr 0. Daher sollten Sie immer bei "Lösung" 1) bleiben! :-)

geho.

0

Vor .net, war ein normales Muster für TryXX Methoden, um einfach das Argument übergeben-durch-Referenz unverändert zu lassen. Dies war ein sehr nützliches Muster, da es diesen Code zu verstehen, die einen Standardwert verwenden wollte, wie etwas tun könnte:

MyNum = 5; 
TryParsing(myString, &myNum); 

während Code, der nicht einen Standardwert verwenden wollte konnte verwenden:

if (TryParsing(myString, &myNum)) 
{ .. code that uses myNum .. } 
else 
{ .. code that doesn't use myNum .. } 

In der früheren Verwendung hätte der aufrufende Code sicherstellen müssen, wurde vor dem Aufruf initialisiert, aber würde nicht über die TryParsing Rückgabewert kümmern müssen. In der letzteren Verwendung müsste sich der aufrufende Code um den Rückgabewert kümmern, aber er müsste myNum vor dem Aufruf nicht initialisieren. Die TryParsing Routine selbst müsste sich nicht darum kümmern, welche Verwendung beabsichtigt war.

C# erlaubt ein solches Muster jedoch nicht sehr gut, es sei denn, TryParsing ist in einer anderen Sprache geschrieben. Entweder TryParsing muss so geschrieben werden, dass der vorherige Wert myNum ohne Vorüberprüfung unbedingt überschrieben wird, der Aufrufer muss ihn unbedingt initialisieren, oder es müssen unterschiedliche Methoden für die beiden Szenarien bereitgestellt werden. Wenn die TryParsing-Methode in einer anderen Sprache geschrieben wäre, könnte sie sich theoretisch wie die alten Methoden verhalten (schreiben Sie das Argument über Erfolg, und lassen Sie es in Ruhe, wenn nicht), während Sie es weiterhin als out-Parameter bezeichnen. Ich würde dies jedoch nicht empfehlen, da das schrullige Verhalten nicht auf diesen Parameter beschränkt wäre.

Betrachten wir zum Beispiel, dass ein Verfahren dieser Art ein Argument vom Typ verwendet fooStruct und fooStruct hatte einen Konstruktor, der aussah:

fooStruct(string st) 
{ 
    fooStruct.TryParse(st, out this); 
} 

Der Compiler würde mit einem solchen Konstruktor vollkommen glücklich sein, da es schreibt "definitiv" this. Auf der anderen Seite, wenn ein anderer Code tut:

while(someCondition) 
{ 
    var s = new fooStruct(someString); 
    ... 
} 

Man könnte erwarten, dass s entweder eine initialisierten Struktur halten (wenn someString gültig ist) oder leer sein (wenn es nicht ist). Nichts über diesen Code würde vorschlagen, dass s seinen Wert zwischen Wiederholungen der Schleife behalten könnte. Aber genau das würde wahrscheinlich passieren.