[C#] Le piège des paramètres nommés et optionnels

8. August 2011 07:08 by Renaud in   //  Tags:   //   Comments (2)

Dans cet article, je vais vous montrer un petit bout de code utilisant les paramètres nommés et optionnels. Ce code est très simple mais il risque fort de vous embrouiller. Et c'est normal, tout y est fait pour!

Si vous êtes encore étudiant, c'est bien le genre de truc vicieux qu'on pourrait vous demander lors d'un test :)

using System;
class Base {
    public virtual void Foo(int x = 4, int y = 5) {
        Console.WriteLine("x:{0}, y:{1}", x, y);
    }
}

class Derived : Base {
    public override void Foo(int y = 4, int x = 5) {
        Console.WriteLine("x:{0}, y:{1}", x, y);
    }
}

class Program {
    static void Main(string[] args) {
        Base b = new Derived();
        b.Foo(y: 5, x: 4);
    }
}
Quel sera le résultat affiché? x:4, y:4 x:4, y:5 x:5, y:4 x:5, y:5

Pendant que vous réfléchissez, je vous explique ce code plus en détail...

Il y a plusieurs choses à remarquer ici:

Les paramètres optionnels: depuis C# 4.0, il est possible de préciser une valeur par défaut pour les paramètres d'une méthode ou d'un constructeur. Si parmi les paramètres, certains n'ont pas de valeur par défaut, il doivent être placés avant les paramètres optionnels de sorte que le compilateur puissé déterminer quelle méthode est appelée sans ambiguïté! Cela permet d'écrire un peu moins de code, comme dans cet exemple:

        public Personne(string nom = "Sans nom", int age = "18"){
            Nom = nom;
            Age = age;
        }

Sans les paramètres optionnels, ce constructeur aurait été écrit avec trois constructeurs:

        public Personne() : this("Sans nom", 18) { }

        public Personne(string nom) : this(nom, 18) { }

        public Personne(string nom, int age){
            Nom = nom;
            Age = age;
        }

Les paramètres nommés: également depuis C#4.0, il est permis de placer des paramètres dans n'importe quel ordre en les nommant. Dans le premier morceau de code, on passe d'abord la valeur de y, et ensuite la valeur de x!

b.Foo(y: 5, x: 4);

La surcharge de méthode: la méthode Foo est virtual dans la classe Base, ce qui permet de la surcharger dans les sous-classe grâce au mot-clé override.

Mais revenons à notre problème:

        Base b = new Derived();
        b.Foo(y: 5, x: 4);

Puisqu'on a surchargé la méthode Foo dans la classe Derived, le polymorphisme va faire que c'est celle-là qui sera exécutée. Mais aussi étrange que cela puisse paraître, le résultat affiché est : x:5, y:4 On vient pourtant de préciser que x = 4 et y = 5! Qu'est-ce qu'il s'est passé alors?

L'explication est en fait très simple, et il suffit d'écrire ce code dans Visual Studio pour s'en rendre compte: si vous tapez b.Foo(, l'IntelliSense vous affiche la signature de la méthode de la classe Base. Cela est bien normal puisqu'on l'appel sur un objet b de type Base.

Lorsqu'on indique de passer  x = 4 et y = 5 à la méthode Foo, il faut donc comprendre qu'on ne parle pas des x et y de la méthode  void Foo(int y, int x) de la classe Derived mais bien de la classe Base! Evidemment, pour rendre la chose plus confuse, les noms ont été inversés dans la surcharge, mais nous aurions pu utiliser d'autres noms: Derived.Foo(int premier, int second).

La correspondance entre arguments d'une méthode virtual et une méthode surchargée se fait sur base de l'ordre ( comme le montre cet incroyable schéma :) ) et non pas du nom des paramètres!

Dans l'exercice, on passe donc  x = 4 et y = 5, en se basant sur les paramètres de la méthode de la classe Base. Ce qui donne y=4 et x=5 dans la méthode surchargée! Voilà pourquoi le résultat de l'impression est x:5, y:4!

C'est donc là qu'est le danger, qui n'en est pas vraiment un puisque Visual Studio clarifie cette situation grâce à l'IntelliSense!

Quoi qu'il en soit, vous voilà prévenus ! :)

[Solution] WP-PageNavi ne fonctionne pas avec Platform Free Edition

7. August 2011 04:08 by Renaud in   //  Tags:   //   Comments (4)
Edit du 10 septembre 2011: fonctionne pour Platform 1.3.5
Pour ce blog, j'utilise Platform dans sa version gratuite, un thème sous licence GNU. Il me semblait à priori normal de pouvoir utiliser un plug-in du style WP-PageNavi, qui permet de faciliter la navigation en remplaçant le peu élégant "← Previous entries / Next entries →" par ceci: Mais, évidemment, ça n'aurait pas été rigolo si tout avait fonctionné du premier coup. Je ne suis pas vraiment un spécialiste de WordPress...  J'ai commencé par installer quelques plugins similaires à celui que cité plus haut avant d'admettre que je n'y arriverais pas comme ça. Quel que soit le plugin testé, rien ne se passait. Finalement j'me suis dit que le thème y était peut-être pour quelque chose. Sorry but I haven't translated this post in english yet! Anyway, you can find the solution to this problem in my comment on the following post: [resolved] Does Platform theme(free edition) support wp-pagenavi plugin?  
Edit du 10 septembre 2011: fonctionne pour Platform 1.3.5
Pour ce blog, j'utilise Platform dans sa version gratuite, un thème sous licence GNU. Il me semblait à priori normal de pouvoir utiliser un plug-in du style WP-PageNavi, qui permet de faciliter la navigation en remplaçant le peu élégant "← Previous entries / Next entries →" par ceci: Mais, évidemment, ça n'aurait pas été rigolo si tout avait fonctionné du premier coup. Je ne suis pas vraiment un spécialiste de WordPress...  J'ai commencé par installer quelques plugins similaires à celui que cité plus haut avant d'admettre que je n'y arriverais pas comme ça. Quel que soit le plugin testé, rien ne se passait. Finalement j'me suis dit que le thème y était peut-être pour quelque chose. J'ai cherché dans les réglages, et ait trouvé ceci dans la catégorie Apparence > PageLines Settings > Template Setup : Voilà ce que je cherchais, le contrôle Pagination du template Posts Page Content! C'est lui qui est responsable de l'horrible "Previous / Next" en bas de page. Je remarque également qu'en cliquant sur Show Section Descriptions, on nous assure que WP-PageNavi est bien supporté. Quelque chose ne fonctionne donc pas correctement. En lisant le readme du WP-PageNavi, j'ai appris qu'on pouvait l'installer manuellement:
In your theme, replace code like this:
<div class="navigation">
	<div class="nav-previous"><?php next_posts_link( __( '<span class="meta-nav">&larr;</span> Older posts', 'twentyten' ) ); ?></div>
	<div class="nav-next"><?php previous_posts_link( __( 'Newer posts <span class="meta-nav">&rarr;</span>', 'twentyten' ) ); ?></div>
</div>
with this:
<?php wp_pagenavi(); ?>
Tout n'est pas perdu dans ce cas :) j'ai donc googlé vite fait tout ça pour trouver quel fichier du thème Platform concerne la pagination, et je découvre le coupable ! wp-content/themes/platform/sections/wp/section.pagination.php Vous pouvez éditer ce fichier en utilisant un client FTP comme FileZilla! Ce fichier contient la classe PageLinesPagination, qui correspond au contrôle Pagination en image ci-dessus! Et voici la partie qui nous intéresse:
function section_template() { ?>
		<?php if(function_exists('wp_pagenavi') && show_posts_nav() && VPRO):?>
			<?php wp_pagenavi(); ?>
		<?php elseif (show_posts_nav()) : ?>
			<div class="page-nav-default fix">
				<span class="previous-entries"><?php next_posts_link(__('&larr; Previous Entries','pagelines')) ?></span>
				<span class="next-entries"><?php previous_posts_link(__('Next Entries &rarr;','pagelines')) ?></span>
			</div><!-- page nav -->
		<?php endif;?>

	<?php }
Remarquez le "&& VPRO" dans le premier test. Cela signifie que même si WP-PageNavi est installé, on ne l'utilisera pas dans la version free de Platform, mais à la place on utilisera la navigation classique indiquée juste en-dessous! Pour que WP-PageNavi s'exécute correctement, il suffit donc d'éditer cette ligne et de supprimer la dernière condition:
<?php if(function_exists('wp_pagenavi') && show_posts_nav()):?>
Il ne reste plus qu'à bidouiller un peu le CSS du plugin pour centrer tout ça un minimum... Le seul bémol, c'est qu'à chaque mise à jour du thème, il faudra corriger cette ligne. J'ai pas vraiment cherché plus loin pour savoir comment faire une solution permanente. Si vous avez une proposition, elle sera la bienvenue dans les commentaires!
J'sais pas si ça valait vraiment la peine d'écrire un article là-dessus, j'avoue, mais ça m'a fait plaisir de trouver la solution et de vous la faire partager! :)
J'ai cherché dans les réglages, et ait trouvé ceci dans la catégorie Apparence > PageLines Settings > Template Setup : Voilà ce que je cherchais, le contrôle Pagination du template Posts Page Content! C'est lui qui est responsable de l'horrible "Previous / Next" en bas de page. Je remarque également qu'en cliquant sur Show Section Descriptions, on nous assure que WP-PageNavi est bien supporté. Quelque chose ne fonctionne donc pas correctement. En lisant le readme du WP-PageNavi, j'ai appris qu'on pouvait l'installer manuellement:
In your theme, replace code like this:
<div class="navigation">
	<div class="nav-previous"><?php next_posts_link( __( '<span class="meta-nav">&larr;</span> Older posts', 'twentyten' ) ); ?></div>
	<div class="nav-next"><?php previous_posts_link( __( 'Newer posts <span class="meta-nav">&rarr;</span>', 'twentyten' ) ); ?></div>
</div>
with this:
<?php wp_pagenavi(); ?>
Tout n'est pas perdu dans ce cas :) j'ai donc googlé vite fait tout ça pour trouver quel fichier du thème Platform concerne la pagination, et je découvre le coupable ! wp-content/themes/platform/sections/wp/section.pagination.php Vous pouvez éditer ce fichier en utilisant un client FTP comme FileZilla! Ce fichier contient la classe PageLinesPagination, qui correspond au contrôle Pagination en image ci-dessus! Et voici la partie qui nous intéresse:
function section_template() { ?>
		<?php if(function_exists('wp_pagenavi') && show_posts_nav() && VPRO):?>
			<?php wp_pagenavi(); ?>
		<?php elseif (show_posts_nav()) : ?>
			<div class="page-nav-default fix">
				<span class="previous-entries"><?php next_posts_link(__('&larr; Previous Entries','pagelines')) ?></span>
				<span class="next-entries"><?php previous_posts_link(__('Next Entries &rarr;','pagelines')) ?></span>
			</div><!-- page nav -->
		<?php endif;?>

	<?php }
Remarquez le "&& VPRO" dans le premier test. Cela signifie que même si WP-PageNavi est installé, on ne l'utilisera pas dans la version free de Platform, mais à la place on utilisera la navigation classique indiquée juste en-dessous! Pour que WP-PageNavi s'exécute correctement, il suffit donc d'éditer cette ligne et de supprimer la dernière condition:
<?php if(function_exists('wp_pagenavi') && show_posts_nav()):?>
Il ne reste plus qu'à bidouiller un peu le CSS du plugin pour centrer tout ça un minimum... Le seul bémol, c'est qu'à chaque mise à jour du thème, il faudra corriger cette ligne. J'ai pas vraiment cherché plus loin pour savoir comment faire une solution permanente. Si vous avez une proposition, elle sera la bienvenue dans les commentaires!
J'sais pas si ça valait vraiment la peine d'écrire un article là-dessus, j'avoue, mais ça m'a fait plaisir de trouver la solution et de vous la faire partager! :)

TextBox

About the author

I'm a developer, blog writer, and author, mainly focused on Microsoft technologies (but not only Smile). I'm Microsoft MVP Client Development since July 2013.

Microsoft Certified Professional

I'm currently working as an IT Evangelist with an awesome team at the Microsoft Innovation Center Belgique, where I spend time and energy helping people to develop their projects. I also give training to enthusiastic developers and organize afterworks with the help of the Belgian community.

MIC Belgique

Take a look at my first book (french only): Développez en HTML 5 pour Windows 8

Développez en HTML5 pour Windows 8

Membre de l'association Fier d'être développeur

TextBox

Month List