web-dev-qa-db-fra.com

C # 4.0 arguments optionnels out / ref

C # 4.0 autorise-t-il les arguments facultatifs out ou ref?

198
Joe Daley

Comme déjà mentionné, ce n'est tout simplement pas autorisé et je pense que cela a un très bon sens. Cependant, pour ajouter quelques détails supplémentaires, voici une citation tirée de la Spécification C # 4. , section 21.1:

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

paramètre fixe:
les attributsopt paramètre-modificateuropt identificateur de type default-argumentopt
default-argument:
= Expression

  • Un fixed-paramètre avec un default-argument est un paramètre optionnel , alors qu'un paramètre-fixe sans un paramètre-défaut est un paramètre obligatoire .
  • Un paramètre requis ne peut pas apparaître après un paramètre facultatif dans une liste-paramètres-formels.
  • Un paramètre ref ou out ne peut pas avoir default-argument.
89
Tomas Petricek

Non.

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

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

// new overload
public bool SomeMethod()
{
    string temp;
    return SomeMethod(out temp);
}

Mise à jour: Si vous avez C # 7. , vous pouvez simplifier:

// new overload
public bool SomeMethod()
{
    return SomeMethod(out _);    // declare out as an inline discard variable
}

(Merci @Oskar/@Reiner pour l'avoir signalé.)

184
Dunc

Non, mais une autre excellente solution consiste à faire en sorte que la méthode utilise une classe de modèle générique pour les paramètres facultatifs, comme suit:

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

Ensuite, vous pouvez l'utiliser comme suit:

public string foo(string value, OptionalOut<int> outResult = null)
{
    // .. do something

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

    return value;
}

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

    string result;
    OptionalOut<int> optional = new OptionalOut<int> ();

    // example: call without the optional out parameter
    result = foo (str);
    Console.WriteLine ("Output was {0} with no optional value used", result);

    // example: call it with optional parameter
    result = foo (str, optional);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional.Result);

    // example: call it with named optional parameter
    foo (str, outResult: optional);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional.Result);
}
63
Robin R

Il existe un moyen de faire cela qui est autorisé par C #. Cela revient au C++ et viole plutôt la belle structure orientée objet de C #.

UTILISEZ CETTE MÉTHODE AVEC ATTENTION!

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

unsafe public void OptionalOutParameter(int* pOutParam = null)
{
    int lInteger = 5;
    // If the parameter is NULL, the caller doesn't care about this value.
    if (pOutParam != null) 
    { 
        // If it isn't null, the caller has provided the address of an integer.
        *pOutParam = lInteger; // Dereference the pointer and assign the return value.
    }
}

Ensuite, appelez la fonction comme ceci:

unsafe { OptionalOutParameter(); } // does nothing
int MyInteger = 0;
unsafe { OptionalOutParameter(&MyInteger); } // pass in the address of MyInteger.

Pour que cela soit compilé, vous devez activer le code non sécurisé dans les options du projet. C’est une solution vraiment bidon qui ne devrait généralement pas être utilisée, mais si vous avez une décision étrange, mystérieuse, inspirée par la gestion, réellement besoin d’un paramètre optionnel out en C #, alors vous pourrez le faire.

27
wizard07KSU

ICYMI: inclus dans les nouvelles fonctionnalités de C # 7.0 énumérées ici , "les mises au rebut" est désormais autorisé en tant que paramètres out sous la forme d'un _, pour vous permettre d'ignorer les paramètres qui vous intéressent:

p.GetCoordinates(out var x, out _); // I only care about x

P.S. si vous vous trompez également avec la partie "out var x", lisez également la nouvelle fonctionnalité sur "Out Variables" sur le lien.

6
jbdeguzman

Non, mais vous pouvez utiliser un délégué (par exemple, Action) comme alternative.

Inspiré en partie par la réponse de Robin R face à une situation où je pensais que je voulais un paramètre optionnel out, j'ai plutôt utilisé un délégué Action. J'ai emprunté son exemple de code à modifier pour pouvoir utiliser Action<int> afin de montrer les différences et les similitudes:

public string foo(string value, Action<int> outResult = null)
{
    // .. do something

    outResult?.Invoke(100);

    return value;
}

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

    string result;
    int optional = 0;

    // example: call without the optional out parameter
    result = foo (str);
    Console.WriteLine ("Output was {0} with no optional value used", result);

    // example: call it with optional parameter
    result = foo (str, x => optional = x);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional);

    // example: call it with named optional parameter
    foo (str, outResult: x => optional = x);
    Console.WriteLine ("Output was {0} with optional value of {1}", result, optional);
}

Cela présente l’avantage que la variable optionnelle apparaisse dans la source comme un int normal (le compilateur l’enveloppe dans une classe de fermeture plutôt que nous l’enveloppons explicitement dans une classe définie par l’utilisateur).

La variable a besoin d'une initialisation explicite car le compilateur ne peut pas supposer que le Action sera appelé avant la fin de l'appel de la fonction.

Il ne convient pas à tous les cas d'utilisation, mais a bien fonctionné pour mon cas d'utilisation réel (une fonction qui fournit des données pour un test unitaire et lorsqu'un nouveau test unitaire nécessite un accès à un état interne non présent dans la valeur de retour).

2
Steve

Utilisez une méthode surchargée sans le paramètre out pour appeler celle avec le paramètre out pour C # 6.0 et versions antérieures. Je ne suis pas sûr de savoir pourquoi un C # 7.0 pour .NET Core est même la bonne réponse pour ce fil de discussion lorsqu'il lui a été spécifiquement demandé si C # 4.0 pouvait avoir un paramètre optionnel out. La réponse est non!

0
Mr_CSharp