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

quel est le meilleur? en un coup d’œil, le paramètre optionnel semble meilleur (moins de code, moins de documentation XML, etc.), mais pourquoi la plupart des classes de bibliothèque MSDN utilisent-elles la surcharge plutôt que des parameters facultatifs?

Y a-t-il une chose particulière à prendre en compte lorsque vous choisissez d’utiliser un paramètre facultatif (ou une surcharge)?

Un bon exemple d’utilisation de ‘Paramètres facultatifs’ en conjonction avec ‘Paramètres nommés’ dans C # 4.0 est qu’il présente une alternative élégante à la surcharge de méthodes où vous surchargez la méthode en fonction du nombre de parameters.

Par exemple, si vous voulez qu’une méthode foo soit appelée / utilisée, foo() , foo(1) , foo(1,2) , foo(1,2, "hello") . Avec la surcharge de méthode, vous implémenteriez la solution comme celle-ci,

 ///Base foo method public void DoFoo(int a, long b, ssortingng 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 parameters facultatifs dans C # 4.0, vous devez implémenter le cas d’utilisation comme suit,

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

Ensuite, vous pouvez utiliser la méthode comme ça – Notez l’utilisation du paramètre nommé –

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

Cet appel prend le paramètre a valeur égale à 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 parameters dans l’ordre tel qu’ils apparaissent dans la signature de la méthode.

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

Un autre avantage de l’utilisation du paramètre nommé est qu’il améliore considérablement la lisibilité et donc la maintenance des méthodes de parameters facultatives.

Notez comment une méthode rend la redondance nécessaire pour définir 3 méthodes ou plus dans la surcharge de méthode. Ce que j’ai trouvé est un bon exemple d’utilisation d’un paramètre facultatif en conjonction avec des parameters nommés.

Les parameters facultatifs fournissent des problèmes lorsque vous les exposez publiquement en tant qu’API. Un renommage d’un paramètre peut entraîner des problèmes. Changer la valeur par défaut entraîne des problèmes (voir par exemple ici pour quelques informations: mises en garde sur les parameters facultatifs de C # 4.0 )

De plus, les parameters optionnels ne peuvent être utilisés que pour les constantes de compilation. Comparez ceci:

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

pour ça

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

Mettre à jour

Voici quelques éléments de lecture supplémentaires lorsqu’un constructeur avec des parameters par défaut ne fonctionne pas bien avec Reflection .

Je crois qu’ils servent à des fins différentes. Les parameters facultatifs concernent les cas où vous pouvez utiliser une valeur par défaut pour un paramètre et le code sous-jacent sera identique:

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

Les surcharges de méthode concernent les parameters mutuellement exclusifs (sous-ensembles de). Cela signifie normalement que vous devez prétraiter certains parameters, ou que vous avez un code différent pour les différentes “versions” de votre méthode (notez que même dans ce cas, certains parameters peuvent être partagés, c’est pourquoi j’ai mentionné “sous-ensembles” ci-dessus) :

 public void SendSurvey(IList 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 )

Celui-ci va presque sans dire, mais:

Toutes les langues ne prennent pas en charge les parameters facultatifs. Si vous souhaitez que vos bibliothèques soient conviviales pour ces langues, vous devez utiliser des surcharges.

Certes, ce n’est même pas un problème pour la plupart des magasins. Mais vous pouvez parier que c’est pourquoi Microsoft n’utilise pas de parameters facultatifs dans la bibliothèque de classes de base.

Les parameters facultatifs doivent être les derniers. Vous ne pouvez donc pas append de paramètre supplémentaire à cette méthode, sauf si elle est également facultative. Ex:

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

Si vous souhaitez append un nouveau paramètre à cette méthode sans le 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 utiliser la surcharge et supprimer la valeur facultative pour ‘otherValue’. Comme ça:

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

Je suppose que vous souhaitez conserver l’ordre des parameters identique.

L’utilisation de parameters facultatifs réduit donc le nombre de méthodes à utiliser dans votre classe, mais est limitée en ce sens qu’elle doit être la dernière.

Mise à jour Lorsque vous appelez des méthodes avec des parameters facultatifs, vous pouvez utiliser des parameters 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 parameters optionnels donnent donc à l’appelant plus de possibilités.

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

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

Alors en appelant ‘MyMethod’ comme ceci:

 MyMethod(100); 

Cela se traduira par 2 appels de méthode. Mais si vous utilisez des parameters facultatifs, il n’y a qu’une seule implémentation de «MyMethod» et, par conséquent, un seul appel de méthode.

Ni l’un ni l’autre n’est définitivement “meilleur” que l’autre. Ils ont tous deux leur place en écrivant un bon code. Des parameters facultatifs doivent être utilisés si les parameters peuvent avoir une valeur par défaut. La surcharge de méthode doit être utilisée lorsque la différence de signature va au-delà de la non définition de parameters pouvant avoir des valeurs par défaut (comme le comportement diffère selon les parameters transmis et ceux qui sont laissés à la valeur 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, ssortingng ssortingngData = null) // these are good candidates for overloading public void DoSomething(Stream data) public void DoSomething(ssortingng 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) { ... } 

Un bon endroit pour utiliser le paramètre facultatif est WCF, car il ne prend pas en charge la surcharge de méthode.

Qu’en est-il d’une troisième option: passer une instance d’une classe avec des propriétés correspondant à divers “parameters facultatifs”.

Cela offre les mêmes avantages que les parameters nommés et facultatifs, mais j’estime que cela est souvent beaucoup plus clair. Cela vous donne l’opportunité de regrouper logiquement les parameters si nécessaire (c.-à-d. Avec la composition) et d’encapsuler également une validation de base.

De plus, si vous vous attendez à ce que les clients qui utilisent vos méthodes pour effectuer toute sorte de métaprogrammation (comme la création d’expressions linq impliquant vos méthodes), je pense que garder la signature de méthode simple présente des avantages.

Ce n’est pas vraiment une réponse à la question initiale, mais plutôt un commentaire sur la réponse de @ NileshGule, mais:

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

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

Nilesh Gule a écrit:

L’un des avantages de l’utilisation de parameters facultatifs est que vous n’avez pas besoin de faire une vérification conditionnelle de vos méthodes, par exemple si une chaîne était nulle ou vide si l’un des parameters d’entrée était une chaîne. Comme il y aurait une valeur par défaut atsortingbuée au paramètre facultatif, le codage défensif sera considérablement réduit.

C’est en fait incorrect, vous devez toujours vérifier les valeurs NULL:

 void DoSomething(ssortingng value = "") // Unfortunately ssortingng.Empty is not a comstack-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 vide, celle-ci ne sera pas remplacée par la valeur par défaut. Donc, vous devez toujours vérifier les parameters d’entrée pour les valeurs NULL.

L’un des avantages de l’utilisation de parameters facultatifs est que vous n’avez pas besoin de faire une vérification conditionnelle de vos méthodes, par exemple si une chaîne était nulle ou vide si l’un des parameters d’entrée était une chaîne. Comme il y aurait une valeur par défaut atsortingbuée au paramètre facultatif, le codage défensif sera considérablement réduit.

Les parameters nommés offrent la possibilité de transmettre des valeurs de parameters dans n’importe quel ordre.

Pour répondre à votre première question,

Pourquoi la plupart des classes de bibliothèque MSDN utilisent-elles la surcharge plutôt que des parameters 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 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 facultative correspondante.

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