web-dev-qa-db-fra.com

Comment pouvez-vous utiliser des paramètres optionnels en C #?

Remarque: Cette question a été posée à un moment où C # ne prenait pas encore en charge les paramètres facultatifs (c'est-à-dire avant C # 4).

Nous construisons une API Web générée par programme à partir d'une classe C #. La classe a la méthode GetFooBar(int a, int b) et l'API a une méthode GetFooBar prenant des paramètres de requête comme &a=foo &b=bar

Les classes doivent prendre en charge des paramètres facultatifs, ce qui n'est pas pris en charge en langage C #. Quelle est la meilleure approche?

418
Kalid

Surpris, personne n’a mentionné les paramètres facultatifs de C # 4.0 qui fonctionnent comme ceci:

public void SomeMethod(int a, int b = 0)
{
   //some code
}

Edit: Je sais qu'au moment où la question a été posée, C # 4.0 n'existait pas. Mais cette question occupe toujours la première place sur Google pour les "arguments optionnels C #", alors je me suis dit que cette réponse méritait d'être ici. Pardon.

930
Alex

Une autre option consiste à utiliser le mot clé params

public void DoSomething(params object[] theObjects)
{
  foreach(object o in theObjects)
  {
    // Something with the Objects…
  }
}

Appelé comme ...

DoSomething(this, that, theOther);
120
Tim Jarvis

En C #, j'utiliserais normalement plusieurs formes de la méthode:

void GetFooBar(int a) { int defaultBValue;  GetFooBar(a, defaultBValue); }
void GetFooBar(int a, int b)
{
 // whatever here
}

MISE À JOUR: Ceci a été mentionné ci-dessus était comme je l'ai fait par défaut avec C # 2.0. Les projets sur lesquels je travaille maintenant utilisent C # 4.0, qui prend désormais directement en charge les paramètres facultatifs. Voici un exemple que je viens d'utiliser dans mon propre code:

public EDIDocument ApplyEDIEnvelop(EDIVanInfo sender, 
                                   EDIVanInfo receiver, 
                                   EDIDocumentInfo info,
                                   EDIDocumentType type 
                                     = new EDIDocumentType(EDIDocTypes.X12_814),
                                   bool Production = false)
{
   // My code is here
}
72
stephenbayer

De ce site:

http://www.tek-tips.com/viewthread.cfm?qid=1500861&page=1

C # autorise l'utilisation de l'attribut [facultatif] (à partir de VB, bien que non fonctionnel en C #). Donc, vous pouvez avoir une méthode comme celle-ci:

using System.Runtime.InteropServices;
public void Foo(int a, int b, [Optional] int c)
{
  ...
}

Dans notre API, nous détectons des paramètres facultatifs (ParameterInfo p.IsOptional) et définissons une valeur par défaut. Le but est de marquer les paramètres comme optionnels sans avoir recours à des kludges comme avoir "optionnel" dans le nom du paramètre.

40
Kalid

Vous pouvez utiliser la surcharge de méthode ...

 GetFooBar () 
 GetFooBar (int a) 
 GetFooBar (int a, int b).

Cela dépend des signatures de la méthode. Dans l'exemple que j'ai donné, il manque la méthode "int b" uniquement car elle aurait la même signature que la méthode "int a".

Vous pouvez utiliser des types Nullable ...

 GetFooBar (int? A, int? B) 

Vous pouvez ensuite vérifier, à l'aide de a.HasValue, si un paramètre a été défini.

Une autre option serait d'utiliser un paramètre 'params'.

 GetFooBar (objet params [] args) 

Si vous voulez utiliser des paramètres nommés, vous devrez créer un type pour les gérer, même si je pense qu’il existe déjà quelque chose comme cela pour les applications Web.

23
Kepboy

Vous pouvez utiliser des paramètres optionnels dans C # 4.0 sans vous inquiéter . Si nous avons une méthode comme:

int MyMetod(int param1, int param2, int param3=10, int param4=20){....}

lorsque vous appelez la méthode, vous pouvez ignorer les paramètres suivants:

int variab = MyMethod(param3:50; param1:10);

C # 4.0 implémente une fonctionnalité appelée "paramètres nommés", vous pouvez réellement passer les paramètres par leurs noms, et bien sûr vous pouvez les passer dans l'ordre de votre choix :) 

20
kristi_io

Bonjour facultatif monde

Si vous souhaitez que le moteur d'exécution fournisse une valeur de paramètre par défaut, vous devez utiliser la réflexion pour passer l'appel. Pas aussi gentil que les autres suggestions pour cette question, mais compatible avec VB.NET.

using System;
using System.Runtime.InteropServices;
using System.Reflection;

namespace ConsoleApplication1
{
    class Class1
    {
        public static void sayHelloTo(
            [Optional,
            DefaultParameterValue("world")] string whom)
        {
            Console.WriteLine("Hello " + whom);
        }

        [STAThread]
        static void Main(string[] args)
        {
            MethodInfo mi = typeof(Class1).GetMethod("sayHelloTo");
            mi.Invoke(null, new Object[] { Missing.Value });
        }
    }
}
17
Hugh Allen

Un moyen simple qui vous permet d’omettre n’importe quel paramètre dans toute position, tire parti de types nullable comme suit:

public void PrintValues(int? a = null, int? b = null, float? c = null, string s = "")
{
    if(a.HasValue)
        Console.Write(a);
    else
        Console.Write("-");

    if(b.HasValue)
        Console.Write(b);
    else
        Console.Write("-");

    if(c.HasValue)
        Console.Write(c);
    else
        Console.Write("-");

    if(string.IsNullOrEmpty(s)) // Different check for strings
        Console.Write(s);
    else
        Console.Write("-");
}

Les chaînes sont déjà des types nullables, elles n'ont donc pas besoin de ?.

Une fois que vous avez cette méthode, les appels suivants sont all valid:

PrintValues (1, 2, 2.2f);
PrintValues (1, c: 1.2f);
PrintValues(b:100);
PrintValues (c: 1.2f, s: "hello");
PrintValues();

Lorsque vous définissez une méthode de cette manière, vous avez la liberté de définir uniquement les paramètres souhaités en en les nommant. Voir le lien suivant pour plus d'informations sur les paramètres nommés et facultatifs:

Arguments nommés et facultatifs (Guide de programmation C #) @ MSDN

11
SteakOverflow

Je suis d'accord avec stephenbayer. Mais comme il s’agit d’un service Web, il est plus facile pour l’utilisateur final d’utiliser une seule forme de la méthode Web que d’utiliser plusieurs versions de la même méthode. Je pense que dans cette situation, les types nullables sont parfaits pour les paramètres facultatifs.

public void Foo(int a, int b, int? c)
{
  if(c.HasValue)
  {
    // do something with a,b and c
  }
  else
  {
    // do something with a and b only
  }  
}
7
Vivek

les paramètres facultatifs sont pour les méthodes. si vous avez besoin d'arguments optionnels pour une classe et que vous êtes:

  • utilisation de c # 4.0: utilise des arguments optionnels dans le constructeur de la classe, solution que je préfère, car plus proche de ce qui est fait avec les méthodes, donc plus facile à retenir. voici un exemple:

    class myClass
    {
        public myClass(int myInt = 1, string myString =
                               "wow, this is cool: i can have a default string")
        {
            // do something here if needed
        }
    }
    
  • en utilisant les versions c # antérieures à c # 4.0: vous devriez utiliser le chaînage des constructeurs (en utilisant le mot clé: this), où les constructeurs plus simples conduisent à un "constructeur maître" ...

    class myClass
    {
        public myClass()
        {
        // this is the default constructor
        }
    
        public myClass(int myInt)
            : this(myInt, "whatever")
        {
            // do something here if needed
        }
        public myClass(string myString)
            : this(0, myString)
        {
            // do something here if needed
        }
        public myClass(int myInt, string myString)
        {
            // do something here if needed - this is the master constructor
        }
    }
    
6
baskinhu

La manière typique dont cela est traité en C #, comme mentionné par Stephen, est de surcharger la méthode. En créant plusieurs versions de la méthode avec différents paramètres, vous créez effectivement des paramètres facultatifs. Dans les formulaires avec moins de paramètres, vous appelez généralement le formulaire de la méthode. Tous les paramètres définissent vos valeurs par défaut lors de l'appel de cette méthode.

2
cfbarbero

Vous pouvez surcharger votre méthode. Une méthode contient un paramètre GetFooBar(int a) et l’autre contient les deux paramètres, GetFooBar(int a, int b)

1
user2933082

Au lieu des paramètres par défaut, pourquoi ne pas simplement construire une classe de dictionnaire à partir de la chaîne de requête passée .. une implémentation presque identique à celle utilisée par les formulaires asp.net avec les chaînes de requête. 

c'est-à-dire Request.QueryString ["a"] 

Cela découplera la classe de feuilles du code factory/boilerplate.


Vous pouvez également vouloir consulter Services Web avec ASP.NET . Les services Web sont une API Web générée automatiquement via des attributs sur les classes C #.

0
Robert Paulson

les paramètres optionnels ne sont que des paramètres par défaut! Je vous suggère de leur donner tous les deux les paramètres par défaut . GetFooBar (int a = 0, int b = 0) si vous n'avez pas de méthode surchargée, cela entraînera un = 0, b = 0 si vous ne transmettez aucune valeur, si vous transmettez 1 valeur, la valeur transmise pour a, 0 et si vous transmettez 2 valeurs, la 1re sera affectée à a et la seconde à b.

espérons que cela répond à votre question.

0
user3555836

Un peu tard pour le parti, mais je cherchais la réponse à cette question et finalement trouvé un autre moyen de le faire. Déclarez les types de données pour les arguments facultatifs de votre méthode Web comme étant de type XmlNode. Si l'argument optionnel est omis, il sera défini sur null et s'il est présent, vous pouvez obtenir sa valeur de chaîne en appelant arg.Value, c'est-à-dire,

[WebMethod]
public string Foo(string arg1, XmlNode optarg2)
{
    string arg2 = "";
    if (optarg2 != null)
    {
        arg2 = optarg2.Value;
    }
    ... etc
}

Ce qui est également décent à propos de cette approche est que la page d’accueil générée par .NET pour ws affiche toujours la liste des arguments (bien que vous perdiez les zones de saisie de texte pratiques pour les tests).

0
Ron K

Par exemple, si quelqu'un souhaite passer un rappel (ou delegate) en tant que paramètre facultatif, vous pouvez le faire de cette façon.

Paramètre de rappel facultatif:

public static bool IsOnlyOneElement(this IList lst, Action callbackOnTrue = (Action)((null)), Action callbackOnFalse = (Action)((null)))
{
    var isOnlyOne = lst.Count == 1;
    if (isOnlyOne && callbackOnTrue != null) callbackOnTrue();
    if (!isOnlyOne && callbackOnFalse != null) callbackOnFalse();
    return isOnlyOne;
}
0
CodeArtist

Je devais le faire dans un service Web VB.Net 2.0. J'ai fini par spécifier les paramètres sous forme de chaînes, puis de les convertir en tout ce dont j'avais besoin. Un paramètre facultatif a été spécifié avec une chaîne vide. Pas la solution la plus propre, mais cela a fonctionné. Veillez simplement à attraper toutes les exceptions qui peuvent se produire.

0
Matt

J'ai un service Web à écrire qui prend 7 paramètres. Chacun est un attribut de requête facultatif à une instruction SQL enveloppée par ce service Web. Deux solutions de contournement pour les paramètres non facultatifs viennent donc à l’esprit ...

method1 (param1, param2, param 3, param 4, param 5, param 6, param7) method1 (param1, param2, param3, param 4, param5, param5, param 6) méthode 1 (param1, param2, param3 , param4, param5, param7) ... commencez à voir la photo. De cette façon se trouve la folie. Beaucoup trop de combinaisons.

Maintenant, pour un moyen plus simple qui semble gênant mais qui devrait fonctionner: Method1 (param1, bool useParam1, param2, bool useParam2, etc ...)

C’est un appel de méthode; les valeurs de tous les paramètres sont obligatoires et chaque cas qu’il contient est traité. Il est également clair comment l'utiliser depuis l'interface.

C'est un hack, mais ça va marcher.

0
Spanky