242 votes

C# 4.0 arguments optionnels out/ref

Est-ce que C# 4.0 autorise des arguments out ou ref optionnels?

2 votes

Eh bien, en C++, elles ont effectivement des paramètres "out" - vous pouvez avoir un argument d'adresse initialisé à null et il est assez courant d'écrire du code de bibliothèque qui ne remplira une structure de retour que si le pointeur n'est pas nul. C'est un idiome qui remonte à l'utilisation de null pour les "arguments optionnels" dans les API C.

61 votes

@Ed et tout le monde: pourquoi cela n'aurait aucun sens? Si une fonction "retourne" une valeur via "out", je ne veux pas être obligé de l'accepter. Maintenant je sais que pour des raisons techniques le compilateur doit toujours passer quelque chose en, mais il n'y a aucune raison pour laquelle il ne pourrait pas simplement créer un local factice pour moi derrière mon dos.

6 votes

Peut-être que cela n'a pas de sens du point de vue de la façon dont les choses sont mises en œuvre ou de ce qu'est réellement un paramètre facultatif. Mais comme l'a dit romkyns, ce serait vraiment bien d'avoir des "arguments de sortie facultatifs" - interprétez cela en anglais plutôt qu'en CLR et cela devient raisonnable et, à mon avis, souhaitable.

250voto

Dunc Points 4360

Non.

Une solution de contournement consiste à surcharger avec une autre méthode qui ne possède pas de paramètres out / ref, et qui appelle simplement votre méthode actuelle.

public bool SomeMethod(out string input)
{
    ...
}

// nouvelle surcharge
public bool SomeMethod()
{
    string temp;
    return SomeMethod(out temp);
}

Si vous avez C# 7.0, vous pouvez simplifier :

// nouvelle surcharge
public bool SomeMethod()
{
    return SomeMethod(out _);    // déclare out comme une variable de rejet inline
}

(Merci à @Oskar / @Reiner d'avoir souligné cela.)

8 votes

Avez-vous une idée pour une solution plus élégante que de déclarer temp/dummy?

22 votes

Qu'est-ce qui n'est pas élégant là-dedans? Ça a l'air parfaitement correct pour moi.

30 votes

Peut-être décent, mais élégant est définitivement sur une autre ligue. Le fait qu'il n'y ait pas de meilleure solution ne signifie pas que cela soit état de l'art par décret.

98voto

Tomas Petricek Points 118959

Comme déjà mentionné, ceci n'est tout simplement pas autorisé et je pense que cela n'a aucun sens. Cependant, pour ajouter quelques détails supplémentaires, voici une citation de la Spécification C# 4.0, section 21.1 :

Les paramètres formels des constructeurs, des méthodes, des indexeurs et des types de délégués peuvent être déclarés optionnels :

paramètre-fixe :
    attributsopt modificateur-paramètreopt type identifiant argument-par-défautopt
argument-par-défaut :
    = expression

  • Un paramètre-fixe avec un argument-par-défaut est un paramètre optionnel, tandis qu'un paramètre-fixe sans un argument-par-défaut est un paramètre requis.
  • Un paramètre requis ne peut pas apparaître après un paramètre optionnel dans une liste de paramètres formels.
  • Un paramètre ref ou out ne peut pas avoir d'argument-par-défaut.

0 votes

Alternativement, vous pouvez créer une surcharge avec un paramètre ref/out. Oui, vous aurez deux définitions de fonctions, mais cela permettra d'obtenir ce que vous voulez.

0 votes

Pas si vous avez 10 paramètres de référence optionnels. Ensuite, vous avez un énorme désordre lors de la tentative de portage vers C#

71voto

Robin R Points 211

Non, mais une autre excellente alternative consiste à utiliser la méthode d'une classe de modèle générique pour les paramètres facultatifs comme suit :

public class OptionalOut
{
    public Type Result { get; set; }
}

Vous pouvez ensuite l'utiliser comme suit :

public string foo(string value, OptionalOut outResult = null)
{
    // .. faire quelque chose

    if (outResult != null) {
        outResult.Result = 100;
    }

    return value;
}

public void bar ()
{
    string str = "bar";

    string result;
    OptionalOut optional = new OptionalOut ();

    // exemple : appel sans le paramètre facultatif de sortie
    result = foo (str);
    Console.WriteLine ("La sortie était {0} sans utilisation de la valeur facultative", result);

    // exemple : l'appeler avec le paramètre facultatif
    result = foo (str, optional);
    Console.WriteLine ("La sortie était {0} avec la valeur facultative de {1}", result, optional.Result);

    // exemple : l'appeler avec le paramètre facultatif nommé
    foo (str, outResult: optional);
    Console.WriteLine ("La sortie était {0} avec la valeur facultative de {1}", result, optional.Result);
}

20 votes

C'est une solution très raisonnable, mais une chose à garder à l'esprit est que le compilateur ne forcera pas la nécessité que le paramètre de sortie soit assigné avant de quitter la méthode.

2 votes

J'aime ça, mais si vous ne voulez pas créer une nouvelle classe, vous pouvez le simuler en passant un tableau à un seul élément.

0 votes

Est-ce que quelqu'un pourrait s'il vous plaît élaborer là-dessus : "le compilateur n'imposera pas la nécessité que le paramètre de sortie soit assigné avant de sortir de la méthode"?

34voto

wizard07KSU Points 56

Il existe en fait une façon de faire cela qui est autorisée par C#. Cela renvoie à C++, et viole plutôt la belle structure orientée objet de C#.

UTILISEZ CETTE MÉTHODE AVEC PRÉCAUTION!

Voici comment vous déclarez et écrivez votre fonction avec un paramètre optionnel :

unsafe public void OptionalOutParameter(int* pOutParam = null)
{
    int lInteger = 5;
    // Si le paramètre est NULL, l'appelant ne se préoccupe pas de cette valeur.
    if (pOutParam != null) 
    { 
        // S'il n'est pas null, l'appelant a fourni l'adresse d'un entier.
        *pOutParam = lInteger; // Dé référencez le pointeur et assignez la valeur de retour.
    }
}

Ensuite, appelez la fonction comme ceci :

unsafe { OptionalOutParameter(); } // ne fait rien
int MonEntier = 0;
unsafe { OptionalOutParameter(&MonEntier); } // passe en argument l'adresse de MonEntier.

Pour que cela compile, vous devrez activer le code non sécurisé dans les options du projet. Il s'agit d'une solution vraiment bricolée qui ne devrait généralement pas être utilisée, mais si pour une raison étrange, mystérieuse, inspirée par la gestion, vous avez VRAIMENT besoin d'un paramètre out optionnel en C#, alors cela vous permettra de le faire.

8voto

jbdeguzman Points 417

ICYMI: Inclus dans les nouvelles fonctionnalités de C# 7.0 énuméré ici, les "discards" sont maintenant autorisés en tant que paramètres de sortie sous la forme d'un _, pour vous permettre d'ignorer les paramètres de sortie qui ne vous intéressent pas :

p.GetCoordinates(out var x, out _); // Je me soucie seulement de x

P.S. Si vous êtes également confus avec la partie "out var x", lisez la nouvelle fonctionnalité sur les "Out Variables" sur le lien également.

0 votes

Est-ce _ ou * "p.GetCoordinates(out int x, out *); // Je ne m'intéresse qu'à x"

0 votes

Il semblerait que j'étais en train de consulter une version antérieure du document.

0 votes

Les rejets ne sont pas vraiment des variables optionnelles. C'est juste un peu de sucre syntaxique au niveau du code appelant. La fonction elle-même n'a pas connaissance qu'elle a été appelée avec un rejet.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X