Domanda

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

public int GetValue(); 

o

public void GetValue(out int x);

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

Grazie.

È stato utile?

Soluzione

I valori restituiti sono quasi sempre la scelta giusta quando il metodo non ha nient'altro da restituire. (In effetti, non riesco a pensare a nessun caso in cui mai desidererei un metodo void con un parametro out , se potessi scegliere. Decostruire i metodi per la decostruzione supportata dal linguaggio costituisce un'eccezione molto, molto rara a questa regola.)

A parte tutto, impedisce al chiamante di dichiarare la variabile separatamente:

int foo;
GetValue(out foo);

vs

int foo = GetValue();

I valori out impediscono anche il concatenamento dei metodi in questo modo:

Console.WriteLine(GetValue().ToString("g"));

(In effetti, questo è uno dei problemi anche con i setter di proprietà, ed è per questo che il modello del builder utilizza metodi che restituiscono il builder, ad esempio myStringBuilder.Append (xxx) .Append (yyy) . )

Inoltre, i parametri out sono leggermente più difficili da usare con la riflessione e di solito rendono anche più difficili i test. (Di solito viene fatto uno sforzo maggiore per rendere più semplice deridere i valori di ritorno rispetto ai parametri di uscita). Fondamentalmente non riesco a pensare che rendano più facile ...

Valori di ritorno FTW.

EDIT: in termini di ciò che sta succedendo ...

Fondamentalmente quando passi un argomento per un " out " parametro, devi passare in una variabile. (Anche gli elementi dell'array sono classificati come variabili.) Il metodo che chiami non ha un " nuovo " variabile nel suo stack per il parametro: utilizza la variabile per l'archiviazione. Eventuali modifiche alla variabile sono immediatamente visibili. Ecco un esempio che mostra la differenza:

using System;

class Test
{
    static int value;

    static void ShowValue(string description)
    {
        Console.WriteLine(description + value);
    }

    static void Main()
    {
        Console.WriteLine("Return value test...");
        value = 5;
        value = ReturnValue();
        ShowValue("Value after ReturnValue(): ");

        value = 5;
        Console.WriteLine("Out parameter test...");
        OutParameter(out value);
        ShowValue("Value after OutParameter(): ");
    }

    static int ReturnValue()
    {
        ShowValue("ReturnValue (pre): ");
        int tmp = 10;
        ShowValue("ReturnValue (post): ");
        return tmp;
    }

    static void OutParameter(out int tmp)
    {
        ShowValue("OutParameter (pre): ");
        tmp = 10;
        ShowValue("OutParameter (post): ");
    }
}

Risultati:

Return value test...
ReturnValue (pre): 5
ReturnValue (post): 5
Value after ReturnValue(): 10
Out parameter test...
OutParameter (pre): 5
OutParameter (post): 10
Value after OutParameter(): 10

La differenza è nella "quot" post " passaggio - ovvero dopo che la variabile locale o il parametro è stato modificato. Nel test ReturnValue, questo non fa differenza per la variabile statica value . Nel test OutParameter, la variabile value viene modificata dalla riga tmp = 10;

Altri suggerimenti

Cosa c'è di meglio, dipende dalla tua situazione particolare. Uno dei motivi per cui out è quello di facilitare la restituzione di più valori da una chiamata di 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 vorresti usare un semplice ritorno, a meno che tu non abbia la situazione sopra per esempio.

Modifica Questo è un esempio che dimostra uno dei motivi per cui esiste la parola chiave. Quanto sopra non può in alcun modo essere considerato una buona pratica.

Generalmente dovresti preferire un valore di ritorno a un parametro out. I nostri params sono un male necessario se ti ritrovi a scrivere codice che deve fare 2 cose. Un buon esempio di ciò è il modello Try (come Int32.TryParse).

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

int foo = GetValue();

Nota che posso dichiarare una variabile e assegnarla tramite il tuo metodo in una riga. Per il secondo esempio sembra così ...

int foo;
GetValue(out foo);

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

Aggiorna

Un buon posto in cui cercare quando si pongono questi tipi di domande sono le Linee guida per la progettazione di .NET Framework. 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 elementi da un'API, racchiuderli in una struttura / classe sarebbe meglio di un parametro fuori.

C'è un motivo per usare un parametro out che non è già stato menzionato: il metodo chiamante è obbligato a riceverlo. Se il tuo metodo produce un valore che il chiamante non deve scartare, rendendolo un out forza il chiamante ad accettarlo specificamente:

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

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

Naturalmente il chiamante può ancora ignorare il valore in un parametro out , ma tu hai attirato la sua attenzione su di esso.

Questa è un'esigenza rara; più spesso, dovresti usare un'eccezione per un vero problema o restituire un oggetto con informazioni sullo stato per un "FYI", ma potrebbero esserci circostanze in cui questo è importante.

È la preferenza principalmente

Preferisco i resi e se hai più resi puoi includerli in un DTO risultato

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

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 modello TryParse .

Puoi avere un solo valore di ritorno mentre puoi avere più parametri di uscita.

In questi casi devi considerare solo i parametri.

Tuttavia, se è necessario restituire più di un parametro dal metodo, probabilmente si desidera esaminare ciò che si sta tornando da un approccio OO e considerare se è meglio restituire un oggetto o una struttura con questi parametri . Pertanto, ritorni di nuovo a un valore di ritorno.

Preferirei quanto segue anziché uno di quelli in questo semplice esempio.

public int Value
{
    get;
    private set;
}

Ma sono tutti praticamente uguali. Di solito, si userebbe 'out' solo se è necessario restituire più valori dal metodo. Se si desidera inviare un valore dentro e fuori dal metodo, si sceglierebbe 'ref'. Il mio metodo è il migliore, se stai solo restituendo un valore, ma se vuoi passare un parametro e recuperare un valore, uno probabilmente sceglierebbe la tua prima scelta.

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

Se si utilizza return, i dati vengono prima scritti nello stack dei metodi e poi in quelli del metodo chiamante. Mentre in caso di out, viene scritto direttamente nello stack dei metodi di chiamata. Non sono sicuro se ci siano altre differenze.

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

Tuttavia ci sono alcune lievi differenze, ma nessuna di esse è davvero importante:

L'uso del parametro out ti impone di usare due righe come:

int n;
GetValue(n);

mentre usi il valore di ritorno ti permetterà di farlo in una riga:

int n = GetValue();

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

Come altri hanno già detto: restituisce valore, non fuori parametro.

Posso consigliarti il ??libro "Linee guida per la progettazione di strutture" (2a edizione)? 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.

Insieme alle linee guida di progettazione del framework è l'uso dello strumento di analisi statica, FxCop. Lo troverai sui siti di Microsoft come download gratuito. Esegui questo sul tuo codice compilato e vedi cosa dice. Se si lamenta di centinaia e centinaia di cose ... non fatevi prendere dal panico! Osserva con calma e attenzione ciò che dice su ogni singolo caso. Non abbiate fretta di riparare le cose al più presto. Impara da cosa ti sta dicendo. Sarai messo sulla strada della maestria.

Penso che uno dei pochi scenari in cui sarebbe utile sarebbe quando si lavora con la memoria non gestita, e si desidera rendere evidente che il messaggio "restituito" il valore deve essere eliminato manualmente, anziché aspettarsi che venga eliminato da solo.

Inoltre, i valori di ritorno sono compatibili con i paradigmi di progettazione asincroni.

Non puoi designare una funzione " asincrona " se utilizza parametri ref o out.

In sintesi, Valori di ritorno consentono il concatenamento dei metodi, una sintassi più pulita (eliminando la necessità per il chiamante di dichiarare variabili aggiuntive) e consentire la progettazione asincrona senza la necessità di modifiche sostanziali in futuro.

L'uso della parola chiave out con un tipo di ritorno bool, a volte può ridurre il gonfiore del codice e aumentare la leggibilità. (Principalmente quando le informazioni extra nel parametro out sono 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;
        }
    }
}

out è più utile quando si tenta di restituire un oggetto dichiarato nel metodo.

Esempio

public BookList Find(string key)
{
   BookList book; //BookList is a model class
   _books.TryGetValue(key, out book) //_books is a concurrent dictionary
                                     //TryGetValue gets an item with matching key and returns it into book.
   return book;
}

valore restituito è il valore normale che viene restituito dal tuo 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 è che ref dovrebbe essere inizializzato prima e out no

Sospetto di non dare un'occhiata a questa domanda, ma sono un programmatore con esperienza molto e spero che alcuni dei lettori più aperti presteranno attenzione.

Credo che si adatti meglio ai linguaggi di programmazione orientati agli oggetti perché le loro procedure di ritorno del valore (VRP) siano deterministiche e pure.

'VRP' è il nome accademico moderno per una funzione chiamata come parte di un'espressione e ha un valore di ritorno che sostituisce teoricamente la chiamata durante la valutazione dell'espressione. Per esempio. in una dichiarazione come x = 1 + f (y) la funzione f funge da VRP.

'Deterministico' significa che il risultato della funzione dipende solo dai valori dei suoi parametri. Se lo chiami di nuovo con gli stessi valori di parametro, sei certo di ottenere lo stesso risultato.

'Puro' non significa effetti collaterali: chiamare la funzione non fa nulla tranne calcolando il risultato. Questo può essere interpretato nel senso che non significa importanti effetti collaterali, in pratica, quindi se il VRP genera un messaggio di debug ogni volta che viene chiamato, ad esempio, probabilmente può essere ignorato.

Quindi, se, in C #, la tua funzione non è deterministica e pura, dico che dovresti renderla una funzione void (in altre parole, non un VRP), e qualsiasi valore necessario return deve essere restituito in un parametro out o ref .

Ad esempio, se si dispone di una funzione per eliminare alcune righe da una tabella del database e si desidera che restituisca il numero di righe che è stato eliminato, è necessario dichiararlo in questo modo:

void pubblico DeleteBasketItems (categoria BasketItemCategory, conteggio int int);

Se a volte vuoi chiamare questa funzione ma non ottieni il count , potresti sempre dichiarare un sovraccarico.

Potresti voler sapere perché questo stile si adatta meglio alla programmazione orientata agli oggetti. In linea di massima, si adatta a uno stile di programmazione che potrebbe essere (un po 'imprecisamente) definito "programmazione procedurale", ed è uno stile di programmazione procedurale che si adatta meglio alla programmazione orientata agli oggetti.

Perché? Il modello classico di oggetti è che hanno proprietà (aka attributi), e tu interroghi e manipoli l'oggetto (principalmente) attraverso la lettura e l'aggiornamento di tali proprietà. Uno stile di programmazione procedurale tende a semplificare tale operazione, poiché è possibile eseguire codice arbitrario tra operazioni che ottengono e impostano proprietà.

L'aspetto negativo della programmazione procedurale è che, poiché è possibile eseguire codice arbitrario ovunque, è possibile ottenere alcune interazioni molto ottuse e vulnerabili ai bug tramite variabili globali ed effetti collaterali.

Quindi, in parole povere, è buona norma segnalare a qualcuno che legge il tuo codice che una funzione potrebbe avere effetti collaterali rendendola senza valore.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top