2010-03-15 13 views
5

Ipotizzando un metodo con la seguente firmaQual è il comportamento standard per un parametro out quando un metodo TryXxxx restituisce false?

bool TryXxxx(object something, out int toReturn) 

cosa è accettabile per toReturn per essere se TryXxxx restituisce false?

In questo si deduce che lo toReturn non dovrebbe mai essere utilizzato se l'errore TryXxxx non ha importanza?

Se toReturn era un tipo nulable, allora avrebbe senso restituire null. Ma int non è annullabile e non voglio forzarlo.

Se toReturn è sempre un determinato valore se TryXxxx fallisce si rischia di avere la posizione in cui 2 valori potrebbero essere considerati per indicare la stessa cosa. Riesco a vedere questo che porta a una possibile possibile confusione se il valore "predefinito" è stato restituito come risposta valida (quando TryXxxx restituisce true).

Da un punto di implementazione se la vista sembra avere toReturn un valore [ny] è più semplice, ma c'è qualcosa di più importante da considerare?

risposta

6

vorrei esplicitamente documento come utilizzare il valore di default per il tipo (qualunque cosa questo tipo è, così 0 in questo caso, ma default(T) in un caso più generale). Esistono vari casi in cui il valore predefinito è esattamente ciò che si desidera se il valore non è presente, e in tal caso si può semplicemente ignorare il valore restituito dal metodo.

Si noti che questo è ciò che fanno i metodi int.TryParse e Dictionary.TryGetValue.

+0

Inoltre, se il risultato ti interessa abbastanza da non voler utilizzare il valore predefinito, a meno che non fosse esplicitamente il valore che era XYZ (analizzato, ecc.), quindi dovresti davvero controllare il valore di ritorno dal metodo in ogni caso. –

+0

Non avevo pensato che il consumatore avesse un motivo per usare il valore restituito se Prova restituito falso. –

4

Potrebbe essere default(int):

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

direi default, ma in realtà non dovrebbe importare. La convenzione con TryX è che il chiamante deve controllare il valore restituito e utilizzare solo il parametro out quando il metodo restituisce true.

2

Fondamentalmente è qualcosa. Lo avrei documentato come "non definito". Valori ragionevoli sono:

  • predefinito()
  • MINVALUE, MaxCValue, newValue (come new int()), null
  • valore NAN (Double.NaN)

Ma in generale, Direi davvero "non definito" e non dare alle persone qualcosa su cui potrebbero provare a fare affidamento.

+0

In teoria, è possibile documentare il metodo come un comportamento "non definito", ma in realtà è necessario fornire un'implementazione concreta. Sì, è possibile restituire un valore casuale, per provocare la comparsa di bug in sospeso, ma una soluzione pratica è di solito restituire un valore predefinito fisso, quindi "default (T)" è probabilmente il valore migliore. Si noti inoltre che in questo caso è comunque possibile documentare il metodo come un comportamento non definito, che offre la possibilità di modificare il valore in un secondo momento, se necessario. Tuttavia, probabilmente restituirei un valore predefinito fisso. –

0

1) In realtà, penso che non dovrebbe avere importanza perché è necessario sempre controllare il risultato booleano di tali metodi prima di elaborare il valore. Ecco a cosa servono i metodi TryXXX.

2) Tuttavia, in tali casi, faccio sempre riferimento all'implementazione nel framework .NET per garantire la coerenza.E una rapida occhiata in Reflector indica che il tipo Int32 restituisce 0 se l'analisi non è riuscita:

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; 
} 

Tuttavia, non conoscendo i dettagli di implementazione, può ancora accadere che il problema di analisi si verifica quando è già stato assegnato un valore (in parte). In questo caso, il valore potrebbe non essere più 0. Pertanto, si dovrebbe sempre attenersi a "soluzione" 1)! :-)

gehho.

0

Prima di .net, un modello normale era per i metodi TryXX per lasciare semplicemente l'argomento passato per riferimento non modificato. Questo è stato un modello molto utile, dal momento che ha fatto sì che il codice che ha voluto utilizzare un valore di default potrebbe fare qualcosa di simile:

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

mentre il codice che non si desidera utilizzare un valore predefinito potrebbe utilizzare:

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

Nel primo utilizzo, il codice chiamante avrebbe dovuto garantire l'inizializzazione di myNum prima della chiamata, ma non avrebbe dovuto preoccuparsi del valore di ritorno TryParsing. Nell'ultimo utilizzo, il codice chiamante dovrebbe preoccuparsi del valore restituito, ma non dovrebbe inizializzare myNum prima della chiamata. La stessa routine TryParsing non dovrebbe preoccuparsi dell'uso previsto.

C# non consente molto un tale modello, tuttavia, a meno che lo TryParsing non sia scritto in un'altra lingua. O TryParsing deve essere scritto in modo tale che il valore precedente di myNum venga sovrascritto senza condizioni senza essere stato esaminato, il chiamante deve inizializzarlo incondizionatamente o devono essere forniti metodi diversi per i due scenari. Se il metodo TryParsing è stato scritto in un altro linguaggio, potrebbe in teoria comportarsi come i metodi vecchio stile (scrivere l'argomento in caso di successo e lasciarlo da solo se non lo è) mentre lo si chiama ancora un parametro out. Non lo consiglierei, tuttavia, perché il comportamento bizzarro non sarebbe limitato a quel parametro out.

Si consideri, per esempio, che un metodo di quello stile utilizzato un argomento di tipo fooStruct, e fooStruct aveva un costruttore che sembrava:

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

Il compilatore sarebbe perfettamente felice con una tale costruttore, dal momento che "sicuramente" scrive this. D'altra parte, se qualche altro codice fa:

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

Ci si potrebbe aspettare che s si sono titolari di una struttura inizializzata (se someString è valido) oppure essere vuoto (se non lo è). Nulla su quel codice suggerirebbe che s potrebbe mantenere il suo valore tra le ripetizioni del ciclo. Ciò nonostante, è esattamente ciò che potrebbe accadere.

Problemi correlati