web-dev-qa-db-fra.com

surcharge de méthode vs paramètre facultatif en C # 4.0

quel est le meilleur? En bref, le paramètre facultatif semble meilleur (moins de code, moins de documentation XML, etc.), mais pourquoi la plupart des classes de bibliothèques MSDN utilisent-elles la surcharge au lieu de paramètres facultatifs?

Y a-t-il quelque chose de particulier que vous devez prendre en note lorsque vous choisissez d'utiliser un paramètre facultatif (ou une surcharge)?

114
Louis Rhys

Un bon exemple d'utilisation de 'Paramètres facultatifs' en conjonction avec 'Paramètres nommés' en C # 4.0 est qu'il nous présente une alternative élégante à la surcharge de méthode, qui surchargez la méthode en fonction du nombre de paramètres.

Par exemple, disons que vous souhaitiez que la méthode foo soit appelée/utilisée comme suit: foo(), foo(1), foo(1,2), foo(1,2, "hello"). Avec la méthode surchargée, vous implémenteriez la solution comme ceci,

///Base foo method
public void DoFoo(int a, long b, string c)
{
   //Do something
}  

/// Foo with 2 params only
public void DoFoo(int a, long b)
{
    /// ....
    DoFoo(a, b, "Hello");
}

public void DoFoo(int a)
{
    ///....
    DoFoo(a, 23, "Hello");
}

.....

Avec des paramètres facultatifs en C # 4.0, vous implémenteriez le cas d'utilisation comme suit:

public void DoFoo(int a = 10, long b = 23, string c = "Hello")

Ensuite, vous pouvez utiliser la méthode comme suit - Notez l’utilisation du paramètre nommé -

DoFoo(c:"Hello There, John Doe")

Cet appel prend le paramètre a value à 10 et le paramètre b à 23. Une autre variante de cet appel - notez que vous n'avez pas besoin de définir les valeurs des paramètres dans l'ordre dans lequel elles apparaissent dans la méthode. signature, le paramètre nommé rend la valeur explicite.

DoFoo(c:"hello again", a:100) 

L’utilisation d’un paramètre nommé offre un autre avantage: elle améliore considérablement la lisibilité et, par conséquent, la maintenance du code des méthodes de paramètre facultatives.

Notez qu’une méthode rend à peu près redondant l’obligation de définir 3 méthodes ou plus en surcharge de méthode. Ce que j’ai trouvé est un bon cas d’utilisation pour utiliser un paramètre optionnel en conjonction avec des paramètres nommés.

77
Bikal Lem

Les paramètres facultatifs posent des problèmes lorsque vous les exposez publiquement en tant qu'API. Renommer un paramètre peut entraîner des problèmes. La modification de la valeur par défaut entraîne des problèmes (voir par exemple ici pour quelques informations: mises en garde concernant les paramètres facultatifs de C # 4. )

De plus, les paramètres facultatifs ne peuvent être utilisés que pour les constantes à la compilation. Comparez ceci:

public static void Foo(IEnumerable<string> items = new List<string>()) {}
// Default parameter value for 'items' must be a compile-time constant

pour ça

public static void Foo() { Foo(new List<string>());}
public static void Foo(IEnumerable<string> items) {}
//all good

Mise à jour

Voici quelques éléments de lecture supplémentaires lorsqu'un constructeur avec des paramètres par défaut ne joue pas bien avec Reflection .

57
flq

Je crois qu'ils servent des objectifs différents. Les paramètres facultatifs s'appliquent aux cas où vous pouvez utiliser une valeur par défaut pour un paramètre et où le code sous-jacent sera le même:

public CreditScore CheckCredit( 
  bool useHistoricalData = false,  
  bool useStrongHeuristics = true) { 
  // ... 
}

Les surcharges de méthodes concernent les cas où vous avez des paramètres (sous-ensembles de) mutuellement exclusifs. Cela signifie normalement que vous devez prétraiter certains paramètres ou que vous avez un code totalement différent pour les différentes "versions" de votre méthode (notez que même dans ce cas, certains paramètres peuvent être partagés, c'est pourquoi j'ai mentionné les "sous-ensembles" ci-dessus) :

public void SendSurvey(IList<Customer> customers, int surveyKey) {  
  // will loop and call the other one 
} 
public void SendSurvey(Customer customer, int surveyKey) {  
  ...  
}

(J'ai écrit à ce sujet il y a quelque temps ici )

37
Jordão

Celui-ci va presque sans dire, mais:

Toutes les langues ne prennent pas en charge les paramètres facultatifs. Si vous voulez que vos bibliothèques soient amicales avec ces langues, vous devez utiliser des surcharges.

Certes, ce n'est pas un problème pour la plupart des magasins. Mais vous pouvez parier que c’est la raison pour laquelle Microsoft n’utilise pas de paramètres facultatifs dans la bibliothèque de classes de base.

27
Joe White

Ni l'un ni l'autre n'est définitivement "meilleur" que l'autre. Ils ont tous deux leur place dans la rédaction d'un bon code. Les paramètres facultatifs doivent être utilisés s'ils peuvent avoir une valeur par défaut. La surcharge de méthode doit être utilisée lorsque la différence de signature dépasse le fait de ne pas définir de paramètres pouvant avoir des valeurs par défaut (le comportement varie par exemple en fonction des paramètres passés et laissés à ceux par défaut).

// this is a good candidate for optional parameters
public void DoSomething(int requiredThing, int nextThing = 12, int lastThing = 0)

// this is not, because it should be one or the other, but not both
public void DoSomething(Stream streamData = null, string stringData = null)

// these are good candidates for overloading
public void DoSomething(Stream data)
public void DoSomething(string data)

// these are no longer good candidates for overloading
public void DoSomething(int firstThing)
{
    DoSomething(firstThing, 12);
}
public void DoSomething(int firstThing, int nextThing)
{
    DoSomething(firstThing, nextThing, 0);
}
public void DoSomething(int firstThing, int nextThing, int lastThing)
{
    ...
}
9
Michael Meadows

Les paramètres facultatifs doivent être les derniers. Vous ne pouvez donc pas ajouter de paramètre supplémentaire à cette méthode, à moins que ce ne soit également facultatif. Ex:

void MyMethod(int value, int otherValue = 0);

Si vous souhaitez ajouter un nouveau paramètre à cette méthode sans surcharger, il doit être facultatif. Comme ça

void MyMethod(int value, int otherValue = 0, int newParam = 0);

Si cela ne peut pas être facultatif, vous devez alors utiliser la surcharge et supprimer la valeur facultative de 'otherValue'. Comme ça:

void MyMethod(int value, int otherValue = 0);
void MyMethod(int value, int otherValue, int newParam);

Je suppose que vous voulez garder l'ordre des paramètres.

L'utilisation de paramètres facultatifs réduit donc le nombre de méthodes nécessaires dans votre classe, mais est limité en ce sens qu'elles doivent être les dernières.

Mise à jour Lorsque vous appelez des méthodes avec des paramètres facultatifs, vous pouvez utiliser des paramètres nommés comme ceci:

void MyMethod(int value, int otherValue = 0, int newValue = 0);

MyMethod(10, newValue: 10); // Here I omitted the otherValue parameter that defaults to 0

Les paramètres facultatifs offrent donc plus de possibilités à l'appelant.

Une dernière chose. Si vous utilisez la surcharge de méthode avec une implémentation, procédez comme suit:

void MyMethod(int value, int otherValue)
{
   // Do the work
}

void MyMethod(int value)
{
   MyMethod(value, 0); // Do the defaulting by method overloading
}

Ensuite, lorsque vous appelez 'MyMethod' comme ceci:

MyMethod(100); 

Entraînera 2 appels de méthode. Mais si vous utilisez des paramètres facultatifs, il n'y a qu'une seule implémentation de 'MyMethod' et, par conséquent, un seul appel de méthode.

Le paramètre facultatif approprié est WCF car il ne prend pas en charge la surcharge de méthodes.

4
ashraf

Ce n'est pas vraiment une réponse à la question initiale, mais plutôt un commentaire sur le @ (NilehGule) réponse , mais:

a) Je n'ai pas assez de points de réputation pour commenter

b) Il est assez difficile de lire plusieurs lignes de code dans les commentaires

Nilesh Gule a écrit:

L'un des avantages de l'utilisation de paramètres facultatifs est que vous n'avez pas besoin d'effectuer de vérification conditionnelle dans vos méthodes, comme si une chaîne était nulle ou vide si l'un des paramètres d'entrée était une chaîne. Comme une valeur par défaut serait attribuée au paramètre facultatif, le codage défensif sera réduit dans une large mesure.

C'est en fait incorrect, vous devez toujours vérifier les nulls:

void DoSomething(string value = "") // Unfortunately string.Empty is not a compile-time constant and cannot be used as default value
{
  if(value == null)
    throw new ArgumentNullException();
}

DoSomething(); // OK, will use default value of ""
DoSomething(null); // Will throw

Si vous fournissez une référence de chaîne NULL, elle ne sera pas remplacée par la valeur par défaut. Vous devez donc toujours vérifier les paramètres d'entrée pour les valeurs NULL.

2
Anlo

Qu'en est-il d'une 3ème option: passer une instance d'une classe avec des propriétés correspondant à divers "paramètres optionnels".

Cela offre les mêmes avantages que les paramètres nommés et facultatifs, mais j'estime que cela est souvent beaucoup plus clair. Cela vous donne l’occasion de regrouper logiquement les paramètres si nécessaire (avec la composition) et d’encapsuler une validation de base.

De plus, si vous attendez des clients qui consomment vos méthodes qu'ils fassent toute sorte de métaprogrammation (comme la construction d'expressions linq impliquant vos méthodes), je pense que conserver la signature de méthode simple présente des avantages.

2
Michael Petito

Pour répondre à votre première question,

pourquoi la plupart des classes de bibliothèque MSDN utilisent-elles la surcharge au lieu de paramètres facultatifs?

C'est pour la compatibilité ascendante.

Lorsque vous ouvrez un projet C # 2, 3.0 ou 3.5 dans VS2010, il est automatiquement mis à niveau.

Imaginez simplement le désagrément que cela créerait si chacune des surcharges utilisées dans le projet devait être convertie pour correspondre à la déclaration de paramètre facultatif correspondante.

En outre, comme dit le proverbe, "pourquoi réparer ce qui n’est pas cassé?". Il n'est pas nécessaire de remplacer les surcharges qui fonctionnent déjà avec de nouvelles implémentations.

1
Alex Essilfie

L'un des avantages de l'utilisation de paramètres facultatifs est que vous n'avez pas besoin d'effectuer de vérification conditionnelle dans vos méthodes, comme si une chaîne était nulle ou vide si l'un des paramètres d'entrée était une chaîne. Comme une valeur par défaut serait attribuée au paramètre facultatif, le codage défensif sera réduit dans une large mesure.

Les paramètres nommés offrent la flexibilité de transmettre des valeurs de paramètre dans n'importe quel ordre.

1
Nilesh Gule