c# passaggio - Quale è meglio, valore di ritorno o parametro di uscita?




parametri per (14)

Penso che uno dei pochi scenari in cui sarebbe utile sarebbe quando si lavora con la memoria non gestita, e si vuole rendere ovvio che il valore "restituito" dovrebbe essere smaltito manualmente, piuttosto che aspettarsi che venga smaltito da solo .

Se vogliamo ottenere un valore da un metodo, possiamo usare entrambi i valori restituiti, in questo modo:

public int GetValue(); 

o:

public void GetValue(out int x);

Non capisco davvero le differenze tra loro e, quindi, non so quale sia il migliore. Puoi spiegarmi questo?

Grazie.


Entrambi hanno uno scopo diverso e non sono trattati allo stesso modo dal compilatore. Se il metodo deve restituire un valore, è necessario utilizzare il reso. Out viene utilizzato dove il metodo deve restituire più valori.

Se si utilizza return, i dati vengono prima scritti nello stack dei metodi e quindi nel metodo di chiamata. Mentre in caso di uscita, viene scritto direttamente nello stack dei metodi di chiamata. Non sono sicuro se ci sono altre differenze.


Preferirei la seguente invece di una di quelle in questo semplice esempio.

public int Value
{
    get;
    private set;
}

Ma sono tutti molto simili. Di solito, si dovrebbe usare 'out' solo se hanno bisogno di passare più valori dal metodo. Se vuoi inviare un valore dentro e fuori dal metodo, uno sceglierebbe "ref". Il mio metodo è il migliore, se si restituisce solo un valore, ma se si desidera passare un parametro e ottenere un valore, probabilmente si sceglierà la prima scelta.


C'è un motivo per usare un parametro out che non è già stato menzionato: il metodo di chiamata è obbligato a riceverlo. Se il tuo metodo produce un valore che il chiamante non deve scartare, facendolo out costringe il chiamante ad accettarlo in modo specifico:

 Method1();  // Return values can be discard quite easily, even accidentally

 int  resultCode;
 Method2(out resultCode);  // Out params are a little harder to ignore

Ovviamente il chiamante può ancora ignorare il valore in un parametro out , ma hai richiamato la loro attenzione su di esso.

Questo è un bisogno raro; più spesso, dovresti usare un'eccezione per un problema reale o restituire un oggetto con informazioni di stato per una "FYI", ma potrebbero esserci circostanze in cui ciò è importante.


Dovresti quasi sempre usare un valore di ritorno. I parametri ' out ' creano un po 'di attrito per molte API, composizionalità, ecc.

L'eccezione più degna di nota che viene in mente è quando si desidera restituire più valori (.Net Framework non ha tuple fino alla 4.0), come nel TryParse pattern TryParse .


Come altri hanno detto: valore di ritorno, non fuori parametro.

Posso consigliarti il ​​libro "Framework Design Guidelines" (2a ed)? Le pagine 184-185 illustrano le ragioni per evitare i parametri. L'intero libro ti guiderà nella giusta direzione su tutti i tipi di problemi di codifica .NET.

Allied with Framework Design Guidelines è l'uso dello strumento di analisi statica, FxCop. Lo troverai sui siti di Microsoft come download gratuito. Eseguilo sul tuo codice compilato e guarda cosa dice. Se si lamenta di centinaia e centinaia di cose ... non fatevi prendere dal panico! Guarda con calma e attenzione a ciò che dice su ogni caso. Non abbiate fretta di sistemare le cose al più presto. Impara da ciò che ti sta dicendo. Sarai messo sulla strada della maestria.


Preferisco principalmente

Preferisco i ritorni e se hai più ritorni puoi racchiuderli in un DTO risultato

public class Result{
  public Person Person {get;set;}
  public int Sum {get;set;}
}

Generalmente si dovrebbe preferire un valore di ritorno su un parametro out. I params out sono un male necessario se ti ritrovi a scrivere codice che deve fare 2 cose. Un buon esempio di questo è il pattern Try (come Int32.TryParse).

Consideriamo ciò che il chiamante dei tuoi due metodi dovrebbe fare. Per il primo esempio posso scrivere questo ...

int foo = GetValue();

Si noti che posso dichiarare una variabile e assegnarla tramite il metodo in una riga. Per il 2 ° esempio sembra che questo ...

int foo;
GetValue(out foo);

Ora sono costretto a dichiarare la mia variabile in anticipo ea scrivere il mio codice su due righe.

aggiornare

Un buon posto dove guardare quando si pone questo tipo di domande è il .NET Framework Design Guidelines. Se hai la versione del libro, puoi vedere le annotazioni di Anders Hejlsberg e altri su questo argomento (pagina 184-185) ma la versione online è qui ...

http://msdn.microsoft.com/en-us/library/ms182131(VS.80).aspx

Se ti ritrovi a dover restituire due cose da un'API, allora avvolgerle in una struct / class sarebbe meglio di un out param.


valore di ritorno è il valore normale che viene restituito dal metodo.

Dove come parametro out , well out e ref sono 2 parole chiave di C # che consentono di passare le variabili come riferimento .

La grande differenza tra ref e out è, ref deve essere inizializzato prima e out no


Non c'è alcuna differenza reale, i parametri sono in C # per consentire al metodo di restituire più di un valore, questo è tutto.

Tuttavia ci sono alcune lievi differenze, ma non di loro sono davvero importanti:

L'utilizzo del parametro out ti imporrà di utilizzare due righe come:

int n;
GetValue(n);

durante l'utilizzo del valore di ritorno, ti consente di farlo in una riga:

int n = GetValue();

Un'altra differenza (corretta solo per i tipi di valore e solo se C # non inline la funzione) è che l'uso del valore di ritorno necessariamente farà una copia del valore quando la funzione restituisce mentre usa il parametro OUT non lo farà necessariamente.


Usando la parola chiave out con un tipo di ritorno di bool, a volte è possibile ridurre il bloat del codice e aumentare la leggibilità. (Principalmente quando le informazioni extra nel parametro out vengono spesso ignorate.) Ad esempio:

var result = DoThing();
if (result.Success)
{
    result = DoOtherThing()
    if (result.Success)
    {
        result = DoFinalThing()
        if (result.Success)
        {
            success = true;
        }
    }
}

vs:

var result;
if (DoThing(out result))
{
    if (DoOtherThing(out result))
    {
        if (DoFinalThing(out result))
        {
            success = true;
        }
    }
}

Cosa c'è di meglio, dipende dalla tua situazione particolare. Una delle ragioni è la possibilità di restituire più valori da una chiamata al metodo:

public int ReturnMultiple(int input, out int output1, out int output2)
{
    output1 = input + 1;
    output2 = input + 2;

    return input;
}

Quindi uno non è per definizione migliore dell'altro. Ma di solito si vorrebbe usare un semplice ritorno, a meno che non si abbia la situazione di cui sopra, per esempio.

EDIT: questo è un esempio che dimostra uno dei motivi per cui la parola chiave esiste. Quanto sopra non è in alcun modo considerato una buona pratica.


È possibile avere un solo valore di ritorno mentre è possibile avere più parametri.

Hai solo bisogno di prendere in considerazione i parametri in questi casi.

Tuttavia, se devi restituire più di un parametro dal tuo metodo, probabilmente vorrai esaminare ciò che stai restituendo da un approccio OO e valutare se è meglio restituire un oggetto o una struttura con questi parametri. Quindi sei di nuovo a un valore di ritorno.


Utilizzando i delegati, il seguente codice è in grado di fornire la riusabilità se ci si trova a dover effettuare l'analisi nullable per più di un tipo di struttura. Ho mostrato entrambe le versioni .Parse () e .TryParse () qui.

Questo è un esempio di utilizzo:

NullableParser.TryParseInt(ViewState["Id"] as string);

Ed ecco il codice che ti porta lì ...

public class NullableParser
  {
    public delegate T ParseDelegate<T>(string input) where T : struct;
    public delegate bool TryParseDelegate<T>(string input, out T outtie) where T : struct;
    private static T? Parse<T>(string input, ParseDelegate<T> DelegateTheParse) where T : struct
    {
      if (string.IsNullOrEmpty(input)) return null;
      return DelegateTheParse(input);
    }
    private static T? TryParse<T>(string input, TryParseDelegate<T> DelegateTheTryParse) where T : struct
    {
      T x;
      if (DelegateTheTryParse(input, out x)) return x;
      return null;
    }
    public static int? ParseInt(string input)
    {
      return Parse<int>(input, new ParseDelegate<int>(int.Parse));
    }
    public static int? TryParseInt(string input)
    {
      return TryParse<int>(input, new TryParseDelegate<int>(int.TryParse));
    }
    public static bool? TryParseBool(string input)
    {
      return TryParse<bool>(input, new TryParseDelegate<bool>(bool.TryParse));
    }
    public static DateTime? TryParseDateTime(string input)
    {
      return TryParse<DateTime>(input, new TryParseDelegate<DateTime>(DateTime.TryParse));
    }
  }




c# reference