web-dev-qa-db-fra.com

Comment écarter explicitement un argument sortant?

Je passe un appel:

myResult = MakeMyCall(inputParams, out messages);

mais je ne me soucie pas vraiment des messages. Si c'était un paramètre d'entrée qui ne m'intéressait pas, je passerais simplement un null. Si c'était le retour dont je me fichais, je le laisserais simplement. 

Existe-t-il un moyen de faire quelque chose de similaire avec un out ou dois-je déclarer une variable que je vais ignorer?

75
Andrew Ducker

À partir de C # 7.0, il est possible d’éviter de pré-déclarer des paramètres et de les ignorer.

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

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

64
Nolonar

Vous devez déclarer une variable que vous ignorerez ensuite. C'est généralement le cas du modèle TryParse (ou TryW Whatever), lorsqu'il est utilisé pour tester la validité des entrées utilisateur (par exemple, peut-il être analysé sous forme de nombre?) Sans se soucier de la valeur analysée réelle.

Vous avez utilisé le mot "dispose" dans la question, ce qui, je suppose, était simplement regrettable - mais si le paramètre out est d'un type implémentant IDisposable, vous devez certainement appeler Dispose sauf si la documentation de la méthode indique explicitement que la réception de la valeur ne confère pas la possession. Cependant, je ne me souviens pas avoir jamais vu une méthode avec un paramètre out à jeter, alors j'espère que ce n'est qu'un choix de mots malchanceux.

37
Jon Skeet

Malheureusement, vous devez transmettre quelque chose car la méthode est nécessaire pour le définir. Donc, vous ne pouvez pas envoyer null car la méthode, étant obligée de la définir, exploserait.

Une approche pour masquer la laideur consisterait à envelopper la méthode dans une autre méthode faisant le paramètre out comme vous le souhaitez:

String Other_MakeMyCall(String inputParams)
{
    String messages;

    return MakeMyCall(inputParams, out messages);
}

Vous pouvez ensuite appeler Other_MakeMyCall sans avoir à manipuler les paramètres out dont vous n’avez pas besoin.

36
Andrew Hare

Si la fonction d'origine est déclarée comme ceci:

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

Vous pouvez déclarer une méthode d'extension comme ceci:

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

La méthode d'extension se comportera comme une surcharge qui rend le paramètre out facultatif.

11
bmm6o

Pour ce faire, le compilateur Visual Basic crée une variable factice. C # pourrait le faire, si vous pouvez convaincre Microsoft que c'est une bonne idée.

4
Jonathan Allen

Dans ce cas, j'ai créé une méthode d'extension générique pour ConcurrentDictionary qui n'a pas de méthode Delete ou 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);
}

Appelé à partir d'une instance de ConcurrentDictionary:

ClientList.TryRemoveIgnore(client.ClientId);
0
flodis

Si la classe messages implémente IDisposable, vous ne devriez pas l'ignorer. Considérons quelque chose comme l'approche suivante (la syntaxe n'est peut-être pas correcte car je n'ai pas écrit C # depuis un moment):

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

Une fois en dehors du bloc using, messages sera automatiquement éliminé.

0
Sören Kuklau

Vous devez transmettre une variable pour le paramètre out. Il n'est pas nécessaire d'initialiser la variable avant de la transmettre:

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

En règle générale, vous pouvez simplement ignorer les «messages» après l'appel - sauf si les «messages» doivent être supprimés pour une raison quelconque, telle que l'utilisation de ressources système limitées, auquel cas vous devez appeler Dispose ():

messages.Dispose();

S'il peut utiliser une quantité importante de mémoire et qu'il reste dans la portée pendant un certain temps, il doit probablement être défini sur null s'il s'agit d'un type de référence ou sur une nouvelle instance par défaut s'il s'agit d'un type de valeur. le collecteur peut récupérer la mémoire:

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

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