Come scartare esplicitamente un argomento out?


99

Sto facendo una chiamata:

myResult = MakeMyCall(inputParams, out messages);

ma in realtà non mi interessano i messaggi. Se fosse un parametro di input di cui non mi importava, passerei semplicemente un valore nullo. Se fosse il ritorno di cui non mi importava, lo lascerei semplicemente.

C'è un modo per fare qualcosa di simile con un out, o devo dichiarare una variabile che poi ignorerò?




Grazie! Peccato che non sia nell'ultima versione.
Andrew Ducker

Risposte:


99

A partire da C # 7.0, è possibile evitare di dichiarare in anticipo i parametri e ignorarli.

public void PrintCoordinates(Point p)
{
    p.GetCoordinates(out int x, out int y);
    WriteLine($"({x}, {y})");
}

public void PrintXCoordinate(Point p)
{
    p.GetCoordinates(out int x, out _); // I only care about x
    WriteLine($"{x}");
}

Fonte: https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/


1
Sfortunatamente, questo non è incluso in C # 7 (a partire da aprile 2017).
tia

2
@tia. Ho aggiornato la mia risposta. Apparentemente, il carattere jolly è stato cambiato da *a _. Mi dispiace che ci sia voluto così tanto.
Nolonar

14
Avrebbero dovuto attenersi alla loro idea da utilizzare out voidper la sintassi e il carattere di sottolineatura sembra una scelta strana.
David Anderson

1
@ DavidAnderson-DCOM Anche se non sono un fan del trattino basso, penso che abbiano bisogno del nome del tipo per la risoluzione del sovraccarico.
Jonathan Allen

Sembra che crei ancora un parametro, perché posso aggiungere la riga _ = {a value};dopo la chiamata alla funzione senza errori di compilazione.
Bip901

37

Sfortunatamente ti viene richiesto di passare qualcosa perché il metodo è necessario per impostarlo. Quindi non puoi inviare nullperché il metodo, essendo richiesto per impostarlo, salterebbe.

Un approccio per nascondere la bruttezza sarebbe avvolgere il metodo in un altro metodo che fa il outparametro per te in questo modo:

String Other_MakeMyCall(String inputParams)
{
    String messages;

    return MakeMyCall(inputParams, out messages);
}

Quindi puoi chiamare Other_MakeMyCallsenza dover armeggiare con outparametri che non ti servono.


37

Devi dichiarare una variabile che poi ignorerai. Questo è più comunemente il caso del pattern TryParse (o TryWunque), quando viene utilizzato per testare la validità dell'input dell'utente (ad esempio, può essere analizzato come un numero?) Senza preoccuparsi del valore reale analizzato.

Hai usato la parola "dispose" nella domanda, che sospetto sia stata solo sfortunata, ma se il parametro out è di un tipo che implementa IDisposable, dovresti certamente chiamare Dispose a meno che la documentazione del metodo non dichiari esplicitamente che la ricezione del valore non conferisce Proprietà. Non ricordo di aver mai visto un metodo con un outparametro usa e getta , quindi spero che sia stata solo una scelta di parole sfortunata.


Più di un anti-pattern pragmatico
Jodrell

11

Se la funzione originale è dichiarata in questo modo:

class C
{
    public Result MakeMyCall(Object arg, out List<String> messages);
}

Puoi dichiarare un metodo di estensione come questo:

static class CExtension
{
    public static Result MakeMyCall(this C obj, Object arg)
    {
        List<String> unused;
        return obj.MakeMyCall(arg, out unused);
    }
}

Il metodo di estensione si comporterà come un sovraccarico che rende facoltativo il parametro out.


4

Il compilatore di Visual Basic esegue ciò creando una variabile fittizia. C # potrebbe farlo, se riesci a convincere Microsoft che è una buona idea.


0

Se la classe degli messagesattrezzi IDisposable, non dovresti ignorarla. Considera qualcosa di simile al seguente approccio (potrebbe non essere sintatticamente corretto poiché non scrivo C # da un po '):

using (FooClass messages) {
    myResult = MakeMyCall(inputParams, messages);
}

Una volta fuori dal usingblocco, messagesverrà smaltito automaticamente.


1
Interessante. Ma non devi inizializzare la variabile nell'istruzione using?
OregonGhost

1
@ OregonGhost: Sì, lo fai. E se modifichi il valore della variabile all'interno dell'istruzione using, è ancora il valore originale che viene eliminato.
Jon Skeet,

@ JonSkeet Impossibile cogliere è ancora il valore originale che viene eliminato.
Orkhan Alikhanov,

@OrkhanAlikhanov: il compilatore fondamentalmente prende una copia della variabile all'inizio dell'istruzione using. Quindi la modifica del valore di quella variabile all'interno del blocco non cambia quale oggetto viene eliminato.
Jon Skeet

A proposito, dovrebbe esserci out messages.
Orkhan Alikhanov,

0

È necessario passare una variabile per il parametro out. Non è necessario inizializzare la variabile prima di passarla:

MyMessagesType messages;
myResult = MakeMyCall(inputParams, out messages); 

In genere, puoi semplicemente ignorare i 'messaggi' dopo la chiamata, a meno che i 'messaggi' non debbano essere eliminati per qualche motivo, come l'uso di risorse di sistema limitate, nel qual caso dovresti chiamare Dispose ():

messages.Dispose();

Se potrebbe utilizzare una quantità significativa di memoria e rimarrà nell'ambito per un po ', probabilmente dovrebbe essere impostato su null se si tratta di un tipo di riferimento o su una nuova istanza predefinita se si tratta di un tipo di valore, in modo che la spazzatura il collezionista può recuperare la memoria:

messages = null; // Allow GC to reclaim memory for reference type.

messages = new MyMessageType(); // Allow GC to reclaim memory for value type.

0

In questo caso ho creato un metodo di estensione generico per ConcurrentDictionary che non ha alcun metodo Delete o Remove.

//Remove item from list and ignore reference to removed item
public static void TryRemoveIgnore<K,T>(this ConcurrentDictionary<K,T> dictionary, K key)
{
    T CompletelyIgnored;
    dictionary.TryRemove(key, out CompletelyIgnored);
}

Quando viene chiamato da un'istanza di ConcurrentDictionary:

ClientList.TryRemoveIgnore(client.ClientId);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.