<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Codingly</title>
	<atom:link href="https://codingly.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://codingly.com</link>
	<description>Par Romain Verdier</description>
	<lastBuildDate>Sat, 24 Jun 2017 20:12:35 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='codingly.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>https://secure.gravatar.com/blavatar/ef1fdb0aebf067ec9485ba3ea1fd503472c86ed549f80a97ed9e21b550b87c39?s=96&#038;d=https%3A%2F%2Fs0.wp.com%2Fi%2Fbuttonw-com.png</url>
		<title>Codingly</title>
		<link>https://codingly.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="https://codingly.com/osd.xml" title="Codingly" />
	<atom:link rel='hub' href='https://codingly.com/?pushpress=hub'/>
	<item>
		<title>Arguments nommés et arguments par défaut en C#4</title>
		<link>https://codingly.com/2010/04/18/arguments-nommes-et-arguments-par-defaut-en-c4/</link>
					<comments>https://codingly.com/2010/04/18/arguments-nommes-et-arguments-par-defaut-en-c4/#comments</comments>
		
		<dc:creator><![CDATA[Romain Verdier]]></dc:creator>
		<pubDate>Sun, 18 Apr 2010 19:32:54 +0000</pubDate>
				<category><![CDATA[Posts]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[GuestPost]]></category>
		<guid isPermaLink="false">http://codingly.com/?p=938</guid>

					<description><![CDATA[Guest post de Jb Evain. J&#8217;ai un nouveau pet-peeve [1]. Mais comme pour beaucoup d&#8217;entre eux, c&#8217;est parce que je me suis longtemps fait avoir. Now that I saw the light, et que je ne me trompe guère plus, voir les autres se tromper m&#8217;est tout bonnement insupportable. D&#8217;ailleurs mon introduction est amusante, car beaucoup [&#8230;]]]></description>
										<content:encoded><![CDATA[<p><em>Guest post de <a href="http://evain.net/blog/">Jb Evain</a>.</em></p>
<p>J&rsquo;ai un nouveau <em>pet-peeve</em> [1]. Mais comme pour beaucoup d&rsquo;entre eux, c&rsquo;est parce que je me suis longtemps fait avoir.  Now that I saw the light, et que je ne me trompe guère plus, voir les autres se tromper m&rsquo;est tout bonnement insupportable. D&rsquo;ailleurs mon introduction est amusante, car beaucoup de français ont pour «pet-peeve» l&rsquo;over utilisation des mots anglais dans une phrase française. Moi qui passe ma journée à lire et à écrire de l&rsquo;anglais, ça ne me choque plus, vous savez.<br />
<span id="more-938"></span><br />
Maintenant que vous, fidèle lectorat de Codingly, êtes tiraillé par le suspens,  je me vois mal vous expliquer que c&rsquo;est la mauvaise utilisation d&rsquo;un mot qui cause toute cette ire. Et pourtant, ce matin encore, en lisant mon greader, j&rsquo;ai failli en recracher mon thé équitable. Une personne de plus dans l&rsquo;erreur, bordel ! J&rsquo;en ai ouvert mon Word, et me voici deux paragraphes plus tard. Oui, j&rsquo;en viens au cœur du problème. Problème que l&rsquo;apparition de C#4 n&rsquo;a pas manqué de raviver.</p>
<p>Prenons un exemple de code, compréhensible par tous de 7 à 77 ans. Exception faite de Patrick Smacchia qui dominait la <a href="http://fr.wikipedia.org/wiki/Scène_démo">scène démo</a> bien avant cet âge.</p>
<pre class="brush: csharp; title: ; notranslate">
public static void DoFoo ()
{
    string a = &quot;b&quot;;
    string b = &quot;b2&quot;;
    string c = &quot;g&quot;;
    Foo (a, b, c);
}

public static string Foo (string bar, string baz, string gazonk)
{
    return bar + baz + gazonk;
}

</pre>
<p>Ce code n&rsquo;a, je vous l&rsquo;accorde, ni queue ni tête, et ne sert que le besoin de ma démonstration. Ne nommez pas vos variables ainsi (en plus vous devriez utiliser var, on voit bien que c&rsquo;est un string). Ne refaites donc pas ça au travail. Chez vous, par contre, je dis pas, vous faites ce que vous voulez chez vous après tout.</p>
<p>Bref, détaillons rapidement ce petit bout de code. La méthode <code>Foo</code> a trois paramètres, <code>bar</code>, <code>baz</code> et <code>gazonk</code>. La méthode <code>DoFoo</code> déclare trois variables <code>a</code>, <code>b</code> et <code>c</code>, et appelle la méthode <code>Foo</code> en lui passant en argument le contenu de ses trois variables respectives.</p>
<p>Jusque ici, rien de bien terrible. Utilisons les nouveautés de C#4 maintenant.</p>
<pre class="brush: csharp; title: ; notranslate">
public static void DoFoo ()
{
    string a = &quot;foo&quot;;
    Foo (a);
    Foo (a, gazonk : &quot;GazouGazou&quot;);
}

public static string Foo (string bar, string baz = &quot;baz&quot;, string gazonk = &quot;gaz&quot;)
{
    return bar + baz + gazonk;
}
</pre>
<p>C&rsquo;est vrai que c&rsquo;est amusant. Relisons encore ce que nous voyons. La méthode <code>Foo</code> a toujours trois paramètres, <code>bar</code>, <code>baz</code> et <code>gazonk</code>. Cependant, <code>baz</code> et <code>gazonk</code> ont maintenant une valeur d&rsquo;argument par défaut. Pour le paramètre <code>baz</code>, la valeur <code>"baz"</code> sera passée comme argument par défaut si l&rsquo;appelant n&rsquo;en fournit pas, d&rsquo;argument. Et de même pour le paramètre <code>gazonk</code>, qui aura comme argument par défaut la valeur <code>"gaz"</code>.</p>
<p>La méthode <code>DoFoo</code> devient elle aussi  plus intéressante. Elle appelle la méthode <code>Foo</code> deux fois. La première fois en passant un seul argument à <code>Foo</code>, le contenu de la variable <code>a</code>. Point besoin de passer d&rsquo;autres arguments : le compilateur C# le fera à votre place. En examinant la signature de <code>Foo</code>, pour chaque paramètre définit par <code>Foo</code>, le compilateur va utiliser les valeurs nouvellement spécifiées comme valeurs d&rsquo;arguments par défaut. Il n&rsquo;y a donc pas besoin de passer d&rsquo;argument pour les paramètres <code>baz</code> et <code>gazonk</code>. Après tout, c&rsquo;est pour ça qu&rsquo;on les appelle arguments par défaut.</p>
<p>Le deuxième appel à <code>Foo</code> est tout aussi intéressant. Non seulement on passe toujours comme argument le contenu d&rsquo;une variable pour le paramètre <code>a</code>, mais en plus on spécifie clairement un argument, la valeur  <code>"GazouGazou"</code> en le nommant, <code>gazonk</code>, d&rsquo;après le paramètre définit dans la signature de la méthode <code>Foo</code> auquel on envie que le compilateur C# applique l&rsquo;argument.</p>
<p>Oh je vous entends d&rsquo;ici : </p>
<blockquote><p>Tu nous saoules Jb, ça fait mille ans que c&rsquo;est sorti C#4, et presque autant que je peux les utiliser avec Mono. En plus c&rsquo;est super fastidieux ton explication, t&rsquo;appuies sur tous les mots comme un gamin sur son jouet <a href="http://tykecoons.com/wp-content/uploads/2008/03/j9163_d_1.jpg">fisher price</a>.</p></blockquote>
<p>Et vous auriez raison. Mais les trucs fastidieux c&rsquo;est un peu la <em>raison d&rsquo;être</em>, comme disent les anglais, de Codingly. Donc mon article a tout à fait sa place.</p>
<p>De toute façon personne n&rsquo;a rien compris, c&rsquo;est pas un post sur comment ça marche les arguments nommés en C#4 et les arguments par défaut. C&rsquo;est un post sur la bonne utilisation des mots &laquo;&nbsp;paramètre&nbsp;&raquo; et &laquo;&nbsp;argument&nbsp;&raquo; que tout le monde s&rsquo;amuse à mélanger à loisir, et <a href="http://www.syndicatdelachasse.com/photos/faisan-accouplement.jpg">ce faisant</a>, à ruiner mon bon moral dès le matin. Vous pourriez d&rsquo;ailleurs aller lire <a href="http://en.wikipedia.org/wiki/Parameter_%28computer_science%29#Parameters_and_arguments">Wikipedia</a> ils expliquent mieux que moi.</p>
<p>Vous ne vous rendez pas compte, même les speakers aux <a href="http://www.microsoft.com/france/vision/mstechdays10/Webcast.aspx?EID=c69b7172-b3a7-4d49-96de-e1c5d014aea3">TechDays</a> se mélangent les pinceaux. Il y aurait eu des caténaires entre Lyon et Paris ce jour là, je me serais probablement évanoui dans la salle.</p>
<p>Récapitulons, donc :</p>
<ul>
<li>Les paramètres nommés ne sont pas une nouveauté de C#4, depuis C#1 les paramètres ont des noms, enfin ! Un paramètre est un élément de la signature d&rsquo;une méthode.</li>
<li>Un argument désigne la valeur passée à un paramètre. On peut maintenant nommer les arguments pour gagner en lisibilité. On peut aussi les omettre quand un paramètre définit une valeur d&rsquo;argument par défaut.</li>
</ul>
<p>C&rsquo;est compris, OK ?</p>
<p>[1] <em>Un «pet-peeve», comme vous ne manquez pas de le savoir, c&rsquo;est quelque chose qui vous irrite sans que vous puissiez le contrôler de manière rationnelle.</em></p>
]]></content:encoded>
					
					<wfw:commentRss>https://codingly.com/2010/04/18/arguments-nommes-et-arguments-par-defaut-en-c4/feed/</wfw:commentRss>
			<slash:comments>27</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/b211157a786d649fe89332c92d55cc991f655409b125949b91098bbfddfbca34?s=96&#38;d=https%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">Romain</media:title>
		</media:content>
	</item>
		<item>
		<title>Convertir implicitement des delegates ayant la même signature</title>
		<link>https://codingly.com/2010/02/10/convertir-implicitement-des-delegates-ayant-la-meme-signature/</link>
					<comments>https://codingly.com/2010/02/10/convertir-implicitement-des-delegates-ayant-la-meme-signature/#comments</comments>
		
		<dc:creator><![CDATA[Romain Verdier]]></dc:creator>
		<pubDate>Wed, 10 Feb 2010 22:41:01 +0000</pubDate>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<guid isPermaLink="false">http://codingly.com/?p=891</guid>

					<description><![CDATA[Hier soir, je tombe sur un tweet de Krzysztof Koźmic : Do I care if it&#8217;s Predicate&#60;int&#62; or Func&#60;int&#62;? No, than why won&#8217;t C# compiler just live me alone and pick whatever it needs? I DONT CARE Et là je me dis HAHA LOL MAIS N&#8217;IMPORTE QUOI Predicate&#60;int&#62; et Func&#60;int&#62; c&#8217;est très différent voilà une [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Hier soir, je tombe sur <a href="http://twitter.com/kkozmic/status/8870677911">un tweet</a> de Krzysztof Koźmic :</p>
<blockquote><p>Do I care if it&rsquo;s Predicate&lt;int&gt; or Func&lt;int&gt;? No, than why won&rsquo;t C# compiler just live me alone and pick whatever it needs? I DONT CARE</p></blockquote>
<p>Et là je me dis HAHA LOL MAIS N&rsquo;IMPORTE QUOI <code>Predicate&lt;int&gt;</code> et <code>Func&lt;int&gt;</code> c&rsquo;est très différent voilà une bonne occasion pour moi qui ne suis rien de reprendre gratuitement un des contributeurs principaux de <a href="http://www.castleproject.org/">Castle</a> sur une étourderie. Et je lui fais remarquer, en gros : </p>
<p><span id="more-891"></span></p>
<blockquote><p>Pardon, mais en fait, je crois que <code>Predicate&lt;int&gt;</code> et <code>Func&lt;int&gt;</code> sont des délégués bien différents :)</p></blockquote>
<p>Et tac ! Bon, évidemment, <strike>Krzystzof</strike> <strike>Kzrysztof</strike> Krzysztof pensait bien à <code>Func&lt;int, bool&gt;</code> qui partage effectivement la même signature que <code>Predicate&lt;int&gt;</code>. Son commentaire, pertinent, est donc celui d&rsquo;un programmeur pestant contre le fait que les délégués, en C#, et au niveau même de la CLI, soient des types <a href="http://en.wikipedia.org/wiki/Nominative_type_system">nominatifs</a> et non <a href="http://en.wikipedia.org/wiki/Structural_type_system">structurels</a>.</p>
<p>Considérons les deux types suivants :</p>
<pre class="brush: csharp; title: ; notranslate">
    class Tweet
    {
        public string Message;
    }

    class Buzz
    {
        public string Message;
    }
</pre>
<p>Nous sommes alors ravis de ne pouvoir écrire :</p>
<pre class="brush: csharp; title: ; notranslate">
    Tweet tweet = new Buzz();
</pre>
<p>Car même si structurellement, les instances de <code>Tweet</code> peuvent être considérées compatibles avec les instances de <code>Buzz</code>, sémantiquement c&rsquo;est une autre histoire. Les points en coordonnées cartésiennes ne sont pas des points en coordonnées polaires, les chiens ne sont pas des chats, etc.</p>
<p>Dans le CLR, tous les types sont nominatifs, et c&rsquo;est très bien comme ça. Sauf quand ce n&rsquo;est pas très bien ; Krzysztof et moi pensons par exemple aux délégués.</p>
<p>Le premier problème est qu&rsquo;il est impossible de convertir implicitement une instance de delegate en un autre type de delegate structurellement compatible, e.g. : on ne peut pas &laquo;&nbsp;convertir&nbsp;&raquo; une instance de <code>Func&lt;int, bool&gt;</code> en <code>Predicate&lt;int&gt;</code> :</p>
<pre class="brush: csharp; title: ; notranslate">
    Func&lt;int, bool&gt; func = i =&gt; false;
     
    // La ligne ci-dessous lève une erreur de compilation :
    // Cannot implicitly convert type 'System.Func&lt;int,bool&gt;' to 'System.Predicate&lt;int&gt;'
    Predicate&lt;int&gt; predicate = func;
</pre>
<p>Cependant, il existe plusieurs façons de contourner le problème, dont une particulièrement acceptable :</p>
<pre class="brush: csharp; title: ; notranslate">
EventHandler eventHandler = (s, e) =&gt; {};
Action&lt;object, EventArgs&gt; action;

action = (s,e) =&gt; eventHandler(s,e); // OK, mais lourd.
action = new Action&lt;object, EventArgs&gt;(eventHandler); // OK, mais verbeux.
action = eventHandler.Invoke; // OK tout court.
</pre>
<p>Notons que les deux dernières lignes produisent le même code IL, puisqu&rsquo;on laisse simplement le compilateur générer automatiquement l&rsquo;appel au constructeur de <code>Action&lt;object, EventArgs&gt;</code> à partir du method group <code>Invoke</code> compatible. Quels que soient donc les types de délégués structurellement compatibles avec lesquels on joue, la &laquo;&nbsp;conversion&nbsp;&raquo;, certes explicite, ne coutera que 7 caractères. C&rsquo;est 133 de moins qu&rsquo;un tweet.</p>
<p>Le second problème, plus gênant selon moi, est qu&rsquo;il est impossible aujourd&rsquo;hui de comparer les références de deux instances de délégués structurellement compatibles mais de types différents, alors que selon la sémantique de l&rsquo;opérateur d&rsquo;égalité de <code>Delegate</code>, ça <em>ne devrait pas</em> être gênant :</p>
<pre class="brush: csharp; title: ; notranslate">
Predicate&lt;string&gt; predicate1 = string.IsNullOrEmpty;
Predicate&lt;string&gt; predicate2 = string.IsNullOrEmpty;
Func&lt;string, bool&gt; func = string.IsNullOrEmpty;

if (predicate1 == predicate2) // Vrai
    Console.WriteLine(&quot;predicate1 == predicate2&quot;);

if (predicate1.Equals(func)) // Faux
    Console.WriteLine(&quot;predicate1 == func&quot;);
</pre>
<p>Note : Une <a href="http://msdn.microsoft.com/en-us/library/aa664729%28VS.71%29.aspx">ancienne version</a> de la spécification C# laisse entendre que c&rsquo;était possible :</p>
<blockquote><p>Note that delegates of different types can be considered equal by the above definition, as long as they have the same return type and parameter types.</p></blockquote>
<p>Mais dans la <a href="http://download.microsoft.com/download/3/8/8/388e7205-bc10-4226-b2a8-75351c669b09/CSharp%20Language%20Specification.doc">dernière version</a> spécifie explicitement que c&rsquo;est impossible :</p>
<blockquote><p>If the delegates have different runtime type they are never equal.</p></blockquote>
<p>Bref.</p>
<p>Les plus curieux peuvent alors se demander pourquoi Microsoft n&rsquo;a pas choisit de faire des delegates des types structurels. Lorsqu&rsquo;on se pose une question de ce genre &#8212; et j&rsquo;en profite, amis lecteurs, pour vous poser une petite devinette &#8212; à qui est-il intéressant de la soumettre :</p>
<ul>
<li>Eric Naulleau ?</li>
<li>Eric Zemmour ?</li>
<li>Eric Lippert ?</li>
</ul>
<p>Bravo amis lecteurs, c&rsquo;est effectivement à M. Zemmour que j&rsquo;ai envoyé un mail. Voici donc un extrait de sa réponse :</p>
<blockquote><p>In practice, almost everyone uses delegates structurally, and almost no one makes semantic distinctions between different kinds of delegate types. There&rsquo;s no semantic reason why Predicate and Func couldn&rsquo;t be used interchangeably; they are interesting solely for their structure. (Though of course it is nice if a predicate is a pure function!)</p>
<p>If we had a chance to do it all over again, I think we would make delegates into structural types. Also, note that the new &laquo;&nbsp;no PIA&nbsp;&raquo; feature of C# 4 is essentially structural typing on interfaces. We probably erred a little too far on the side of caution when making all types non-structural in CLR v1, and now we&rsquo;re gradually weakening that.  I would not be too surprised if in some future version of the CLR, it was easier to make structural delegate types, but, no promises.  That&rsquo;s just a speculation.</p></blockquote>
<p>En deux mots, <a href="http://blogs.msdn.com/ericlippert/">Eric Lippert</a> (oui car en fait c&rsquo;est Eric Lippert, hein), m&rsquo;a répondu qu&rsquo;il serait tenté de faire passer les delegates du côté des types structurels s&rsquo;il en avait l&rsquo;occasion, et qu&rsquo;il ne serait pas forcément étonné si cela arrivait dans une version future du CLR.</p>
<p>Stay tuned !</p>
]]></content:encoded>
					
					<wfw:commentRss>https://codingly.com/2010/02/10/convertir-implicitement-des-delegates-ayant-la-meme-signature/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/b211157a786d649fe89332c92d55cc991f655409b125949b91098bbfddfbca34?s=96&#38;d=https%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">Romain</media:title>
		</media:content>
	</item>
		<item>
		<title>Switch sur un type en C#</title>
		<link>https://codingly.com/2009/10/19/switch-sur-un-type-en-c/</link>
					<comments>https://codingly.com/2009/10/19/switch-sur-un-type-en-c/#comments</comments>
		
		<dc:creator><![CDATA[Romain Verdier]]></dc:creator>
		<pubDate>Mon, 19 Oct 2009 18:41:39 +0000</pubDate>
				<category><![CDATA[Posts]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<guid isPermaLink="false">http://codingly.com/?p=872</guid>

					<description><![CDATA[Si vous avez besoin de faire un switch sur un type en C#, la première chose qu&#8217;il vous faut faire est de vous demander si vous avez besoin de faire un switch sur un type. Ensuite, demandez-vous si vous avez vraiment besoin de faire un switch sur un type, et forcez-vous à imaginer une solution [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Si vous avez besoin de faire un switch sur un type en C#, la première chose qu&rsquo;il vous faut faire est de vous demander si vous avez besoin de faire un switch sur un type. Ensuite, demandez-vous si vous avez <em>vraiment </em>besoin de faire un switch sur un type, et forcez-vous à imaginer une solution tirant partie du polymorphisme (c&rsquo;est <em>presque</em> toujours possible). Si pour une raison quelconque (imaginons-la tout de même légitime), vous ne pouvez pas faire autrement, alors voici ce qu&rsquo;il faut éviter de faire :<br />
<span id="more-872"></span></p>
<pre class="brush: csharp; title: ; notranslate">
    switch(expression.GetType().FullName)
    {
        case &quot;System.Linq.Expressions.ConstantExpression&quot;:
            VisitConstantExpression((ConstantExpression) expression);
            break;
        case &quot;System.Linq.Expressions.MemberExpression&quot;:
            VisitMemberExpression((MemberExpression) expression);
            break;
        case &quot;System.Linq.Expressions.MethodCallExpression&quot;:
            VisitMethodCallExpression((MethodCallExpression) expression);
            break;
        case &quot;System.Linq.Expressions.LambdaExpression&quot;:
            VisitLambdaExpression((LambdaExpression) expression);
            break;
        default:
            VisitExpression(expression);
            break;
    }
</pre>
<p>Aussi, si j&rsquo;étais comme tout le monde (note: je ne suis pas comme tout le monde), je ferais une blague à propos de Dieu qui tue des animaux mignons à chaque fois que vous écrivez quelque chose comme :</p>
<pre class="brush: csharp; title: ; notranslate">
    if(expression is ConstantExpression)
        VisitConstantExpression((ConstantExpression)expression);
    else if (expression is MemberExpression)
        VisitMemberExpression((MemberExpression)expression);
    else if (expression is MethodCallExpression)
        VisitMethodCallExpression((MethodCallExpression)expression);
    else if (expression is LambdaExpression)
        VisitLambdaExpression((LambdaExpression)expression);
    else
        VisitExpression(expression);
</pre>
<p>La bonne solution, même si elle paraitra moins concise aux plus taquins d&rsquo;entre vous, est la suivante :</p>
<pre class="brush: csharp; title: ; notranslate">
    var constantExpression = expression as ConstantExpression;
    if (constantExpression != null)
    {
        VisitConstantExpression(constantExpression);
        return;
    }

    var memberExpression = expression as MemberExpression;
    if (memberExpression != null)
    {
        VisitMemberExpression(memberExpression);
        return;
    }

    var methodCallExpression = expression as MethodCallExpression;
    if (methodCallExpression != null)
    {
        VisitMethodCallExpression(methodCallExpression);
        return;
    }

    var lambdaExpression = expression as LambdaExpression;
    if (lambdaExpression != null)
    {
        VisitLambdaExpression(lambdaExpression);
        return;
    }

    VisitExpression(expression);
</pre>
<p>Le safe cast évite la redondance <code>is</code> + cast. Rendons tout de même à césar ce qui est aux taquins : c&rsquo;est un peu verbeux. Heureusement, il est assez facile de factoriser ce genre de code. J&rsquo;utilise pour ma part une implémentation à base de méthodes d&rsquo;extensions, qui ressemble à :</p>
<pre class="brush: csharp; title: ; notranslate">
    public class Switch
    {
        public object Target { get; set; }

        public Switch(object target)
        {
            this.Target = target;
        }
    }
    
    public static class SwitchExtensions
    {
        public static Switch Case&lt;T&gt;(this Switch @this, Action&lt;T&gt; action) where T : class
        {
            if (@this == null)
                return null;

            var t = @this.Target as T;
            if (t == null)
                return @this;

            action(t);
            return null;
        }

        public static void Default(this Switch @this, Action action)
        {
            if (@this == null)
                return;

            action();
        }
    }
</pre>
<p>On retombe alors à l&rsquo;utilisation sur quelque chose de concis et lisible :</p>
<pre class="brush: csharp; title: ; notranslate">
    new Switch(expression)
        .Case&lt;ConstantExpression&gt;(VisitConstantExpression)
        .Case&lt;MemberExpression&gt;(VisitMemberExpression)
        .Case&lt;MethodCallExpression&gt;(VisitMethodCallExpression)
        .Default(() =&gt; VisitExpression(expression));
</pre>
<p>Chaque case prend un délégué en argument. Ici, comme <code>Action&lt;T&gt;</code> matche à chaque fois la signature des méthodes que je veux appeler (<code>Visit</code>*), je passe directement les method groups. Notez qu&rsquo;il est tout à fait possible de faire autrement :</p>
<pre class="brush: csharp; title: ; notranslate">
    new Switch(expression)
        .Case&lt;MemberExpression&gt;(e =&gt; Console.WriteLine(&quot;MemberExpression : &quot; + e))
        .Case&lt;MethodCallExpression&gt;(e =&gt;
                                    {
                                        Console.WriteLine(&quot;Rofl&quot;);
                                        VisitMethodCallExpression(e);
                                        Console.WriteLine(&quot;Lfor&quot;);
                                    });
</pre>
<p>Enfin, pour ne pas que vous vous sentiez trop lésés par cet articlet, voici en prime une photo de pingouin :</p>
<p><img data-attachment-id="875" data-permalink="https://codingly.com/2009/10/19/switch-sur-un-type-en-c/animated-tattoo-1/" data-orig-file="https://codingly.com/wp-content/uploads/2009/10/animated-tattoo-1.jpg" data-orig-size="200,182" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}" data-image-title="Rhino.Tattoo.dll" data-image-description="" data-image-caption="" data-medium-file="https://codingly.com/wp-content/uploads/2009/10/animated-tattoo-1.jpg?w=200" data-large-file="https://codingly.com/wp-content/uploads/2009/10/animated-tattoo-1.jpg?w=200" src="https://codingly.com/wp-content/uploads/2009/10/animated-tattoo-1.jpg?w=720" alt="Rhino.Tattoo.dll" title="Rhino.Tattoo.dll"   class="alignleft size-full wp-image-875" srcset="https://codingly.com/wp-content/uploads/2009/10/animated-tattoo-1.jpg 200w, https://codingly.com/wp-content/uploads/2009/10/animated-tattoo-1.jpg?w=150&amp;h=137 150w" sizes="(max-width: 200px) 100vw, 200px" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://codingly.com/2009/10/19/switch-sur-un-type-en-c/feed/</wfw:commentRss>
			<slash:comments>26</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/b211157a786d649fe89332c92d55cc991f655409b125949b91098bbfddfbca34?s=96&#38;d=https%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">Romain</media:title>
		</media:content>

		<media:content url="https://codingly.com/wp-content/uploads/2009/10/animated-tattoo-1.jpg" medium="image">
			<media:title type="html">Rhino.Tattoo.dll</media:title>
		</media:content>
	</item>
		<item>
		<title>Tout ce que vous n&#8217;avez pas besoin de savoir au sujet du mot clé event</title>
		<link>https://codingly.com/2009/08/17/tout-ce-que-vous-navez-pas-besoin-de-savoir-au-sujet-du-mot-cle-event/</link>
					<comments>https://codingly.com/2009/08/17/tout-ce-que-vous-navez-pas-besoin-de-savoir-au-sujet-du-mot-cle-event/#comments</comments>
		
		<dc:creator><![CDATA[Romain Verdier]]></dc:creator>
		<pubDate>Mon, 17 Aug 2009 19:23:03 +0000</pubDate>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<guid isPermaLink="false">http://codingly.com/?p=797</guid>

					<description><![CDATA[Vous ne vous êtes jamais demandé à quoi servait, en C#, le mot clé event ? Moi oui. Et je vais même jusqu&#8217;à poser la question d&#8217;une certaine façon aux gens qui m&#8217;entourent, sauf peut-être dans la ligne 2 du métro : &#8212; &#160;A quoi ça sert, le mot clé event ? &#8212; &#160;Bah, à [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Vous ne vous êtes jamais demandé à quoi servait, en C#, le mot clé <code>event</code> ? Moi oui. Et je vais même jusqu&rsquo;à poser la question d&rsquo;une certaine façon aux gens qui m&rsquo;entourent, sauf peut-être dans la ligne 2 du métro :</p>
<blockquote><p>&#8212;  &nbsp;A quoi ça sert, le mot clé event ?<br />
&#8212;  &nbsp;Bah, à déclarer des events.<br />
&#8212;  &nbsp;Oui, mais ça marche pas sans le mot clé event ? En écrivant juste, par exemple :<br />
<code>&nbsp;&nbsp;public EventHandler Click;</code><br />
&#8212;  &nbsp;Heu, si, je crois.<br />
&#8212;  &nbsp;Donc, à quoi ça sert, le mot clé event ?<br />
&#8212;  &nbsp;T&rsquo;es relou, dégage.</p></blockquote>
<p>Notez qu&rsquo;à l&rsquo;oral, il n&rsquo;y a pas la coloration syntaxique. Je suppose que c&rsquo;est ce qui conduit assez régulièrement mes interlocuteurs à être désagréables. (J&rsquo;aime pas les gens désagréables !)</p>
<p><span id="more-797"></span></p>
<p>Au risque donc que vous commenciez à m&rsquo;appeler Monsieur Mauclet, j&rsquo;ai bien envie de regrouper dans ce post les principales différences qui existent entre :</p>
<pre class="brush: csharp; title: ; notranslate">public EventHandler Click;</pre>
<p>Et :</p>
<pre class="brush: csharp; title: ; notranslate">public event EventHandler Click;</pre>
<p>Et de combattre au passage certaines confusions, parce que je me sens l&rsquo;âme d&rsquo;un chevalier en ce moment.</p>
<p>Tout d&rsquo;abord &#8212; et c&rsquo;est la différence fondamentale dont découle la plupart des autres &#8212; un event (syntaxiquement assimilable à un champ de type delegate modifié par le mot clé <code>event</code>) n&rsquo;est pas un champ. Il s&rsquo;agit plutôt d&rsquo;une sorte de propriété un peu spéciale revêtant une sémantique particulière : un event est explicitement, heh, un évènement. </p>
<p>Concrètement, écrire :</p>
<pre class="brush: csharp; title: ; notranslate">
public event EventHandler Click;
</pre>
<p> Est équivalent à :</p>
<pre class="brush: csharp; title: ; notranslate">
private EventHandler click;
public event EventHandler Click
{
	add { this.click += value; }
	remove { this.click -= value; }
}
</pre>
<p>Le code ci-dessus est valide en C#. Par défaut, un évènement possède des &laquo;&nbsp;accesseurs&nbsp;&raquo;, <code>add</code> et <code>remove</code>, qui permettent respectivement d&rsquo;ajouter et de supprimer des handlers à un champ privé, de type delegate. Notez qu&rsquo;il s&rsquo;agit ici de l&rsquo;implémentation générée par le compilateur lorsque vous utilisez la déclaration classique d&rsquo;un event, mais il est tout à fait possible de changer cette implémentation : vous êtes en effet libre de mettre ce que vous voulez dans le <code>add</code> et le <code>remove</code>. A vrai dire, un event n&rsquo;est <em>que</em> ce couple <code>add</code>/<code>remove</code>.</p>
<p>Exemple <code>!utile</code> : </p>
<pre class="brush: csharp; title: ; notranslate">
private EventHandler click;
private int handlerCount;
public event EventHandler Click
{
	add 
	{ 
		this.click += value; 
		this.handlerCount++;
	}
	remove
	{ 
		this.click -= value; 
		this.handlerCount--;
	}
}
</pre>
<p>Il est intéressant de faire l&rsquo;analogie entre la façon usuelle de déclarer un event et l&rsquo;écriture d&rsquo;une propriété automatique. Dans les deux cas, le compilateur fait le grunt work, et se charge donc de générer le backing field encapsulé par l&rsquo;event ou la propriété, ainsi que la logique associée (affectation/lecture de la valeur ou ajout/suppression du handler), parce que la plupart du temps, c&rsquo;est effectivement ce que l&rsquo;on désire. Dans les deux cas, au risque de me répéter, il est possible de reprendre la main et de faire ce que l&rsquo;on veut en proposant une implémentation différente des accesseurs (<code>get</code>/<code>set</code> pour les propriétés, <code>add</code>/<code>remove</code> pour les events).</p>
<p>En résumé, un event n&rsquo;est pas un champ, un delegate, ou un truc de facebook ; non, <strong>un event en C# est un moyen d&rsquo;exposer de façon normalisée, deux méthodes permettant d&rsquo;enregistrer/désenregistrer des handlers</strong>. C&rsquo;est tout.</p>
<p>Je crois qu&rsquo;il faut bien faire la différence entre ce qu&rsquo;est un event par définition, et ce que le compilateur génère par défaut pour nous aider. On peut très bien déclarer un event sans avoir de backing field, comme c&rsquo;est aussi le cas pour les propriétés. Un-event-c&rsquo;est-deux-méthodes.</p>
<p>Bon.</p>
<p>Après ce petit rappel, on devrait se sentir un peu plus à l&rsquo;aise pour commencer l&rsquo;énumération inutile de tout ce qui distingue plus ou moins évidemment un <code>event</code> d&rsquo;un Champ Public De Type Delegate (CPDTD).</p>
<h3>Protection</h3>
<p>Lorsque vous exposez un CPDTD, n&rsquo;importe qui est capable de le référencer et de le manipuler en tant que tel. Ce n&rsquo;est pas le cas lorsque vous déclarez un event, puisque seules deux méthodes d&rsquo;ajout/suppression de handler sont exposées. Du coup, l&rsquo;invocation d&rsquo;un event est restreinte : seul le type qui porte l&rsquo;évènement peut déclencher ce dernier, les autres types devant se contenter de fournir leurs handlers en utilisant modestement les accesseurs.</p>
<p>Attention, même les types dérivés perdent le privilège d&rsquo;invocation; on devra donc la plupart du temps prévoir une méthode <code>protected</code> pour contourner la limitation. </p>
<h3>Interfaces</h3>
<p>Puisqu&rsquo;un event-c&rsquo;est-deux-méthodes, il peut apparaitre dans une interface, alors qu&rsquo;un CPDTD, non. C&rsquo;est très important, et très logique. Il est compréhensible en effet qu&rsquo;on puisse s&rsquo;engager à &laquo;&nbsp;exposer&nbsp;&raquo; deux méthodes dans un contrat, mais pas un champ.</p>
<h3>Polymorphisme</h3>
<p>Puisqu&rsquo;un event-c&rsquo;est-deux-méthodes, toujours, on peut parler de polymorphisme, et appliquer aux events les modifiers qu&rsquo;il est habituellement possible d&rsquo;appliquer aux méthodes. Implicitement, ils concerneront les deux accesseurs <code>add</code> et <code>remove</code>. Cela signifie qu&rsquo;un event peut être <code>abstract</code>, <code>virtual</code> ou même <code>sealed</code>. De même, on peut overrider ou redéfinir un event à l&rsquo;aide des mots clés <code>override</code> et <code>new</code>.</p>
<h3>Pas le droit lol</h3>
<p>Le fait qu&rsquo;un event ait toujours des accesseurs (<code>add</code>/<code>remove</code>) implique que les fonctions correspondantes existent déjà. Ainsi, il est impossible d&rsquo;écrire :</p>
<pre class="brush: csharp; title: ; notranslate">
public event EventHandler Click;

public void add_Click(EventHandler handler) {} // Erreur : signature existante
public void remove_Click(EventHandler handler) {} // Erreur : signature existante
</pre>
<h3>Opérateurs</h3>
<p>Lorsqu&rsquo;utilisés avec les delegates, les opérateurs <code>+=</code> et <code>-=</code> ne sont pas interprétés comme la combinaison condensée d&rsquo;une addition/soustraction + une affectation. le type <code>Delegate</code> ne surcharge d&rsquo;ailleurs ni l&rsquo;opérateur <code>+</code>, ni l&rsquo;opérateur <code>-</code>. En fait, le compilateur remplace <code>+=</code> et <code>-=</code> par les appels respectifs aux méthodes statiques <code>Delegate.Combine</code> et <code>Delegate.Remove</code>, qui retournent de nouvelles instances de délégués. (Un délégué est immutable)</p>
<p>Par contre, lorqu&rsquo;on utilise <code>+=</code> et <code>-=</code> pour ajouter/supprimer un handler à un event, le compilateur travaille différemment et se charge d&rsquo;appeller directement les accesseurs de l&rsquo;évènement.</p>
<p>Si <code>Click</code> est un CPDTD :</p>
<pre class="brush: csharp; title: ; notranslate">
button.Click += OnClick;
// Compilé en :
// button.Clik = (EventHandler) Delegate.Combine(button.Clik, new EventHandler(OnClick));
</pre>
<p>Si <code>Click</code> est un event :</p>
<pre class="brush: csharp; title: ; notranslate">
button.Click += OnClick;
// Compilé en :
// button.add_Click(new EventHandler(OnClick));
</pre>
<h3>Warnings</h3>
<p>Puisqu&rsquo;il est uniquement possible de déclencher un évènement à l&rsquo;intérieur de la classe qui contient sa déclaration, le compilateur est capable de lever un warning lorsqu&rsquo;il ne détecte aucune invocation de l&rsquo;évènement.</p>
<h3>Evaluation</h3>
<p>En C#, une affectation est une expression évaluable. On peut écrire, par exemple :</p>
<pre class="brush: csharp; title: ; notranslate">
int i = 12;
int j = i = 6; // (i = 6) est évalué, de type int, donc le code est valide et j vaudra 6.
</pre>
<p>De même, lorsque Click est un CPDTD, il est possible décrire :</p>
<pre class="brush: csharp; title: ; notranslate">EventHandler handler = button.Click += OnClick;</pre>
<p>Car l&rsquo;expression <code>button.Click += OnClick</code> est de type <code>EventHandler</code>.</p>
<p>Mais dans le cas où <code>Click</code> est un event, <code>button.Click += OnClick</code> est de type <code>void</code>, du coup le code précédent ne compile pas.</p>
<h3>Reflection</h3>
<p>Si on veut accéder à un CPDTD par la réflexion, on utilise la méthode <code>GetField</code> ou <code>GetFields</code>. Mais comme les events sont des animaux bien différents, il existe les méthodes <code>GetEvent</code> et <code>GetEvents</code>, qui retournent des instances d&rsquo;<code>EventInfo</code>. J&rsquo;ai insisté là dessus précedemment : la notion d&rsquo;event n&rsquo;est liée à celle de backing field que parce qu&rsquo;il s&rsquo;agit d&rsquo;une association constatée dans 99% des implémentations, mais c&rsquo;est tout. Il est impossible d&rsquo;optenir les métadonnées relatives au backing field d&rsquo;un event à partir de son <code>EventInfo</code>, tout comme il est impossible d&rsquo;obtenir les métadonnées relatives au backing field d&rsquo;une propriété à partir de son <code>PropertyInfo</code>.</p>
<p>Enfin si, <a href="http://evain.net/blog/articles/2009/05/01/getting-the-field-backing-a-property-using-reflection">c&rsquo;est possible</a>, mais chut.</p>
<h3>Interop</h3>
<p>Si vous kiffez COM, sachez que les CPDTD ne vous seront d&rsquo;aucune utilité au cas où vous chercheriez à interopérer avec des évènements COM. Il faudra forcément utiliser des events. Et ne me dites pas que c&rsquo;est évident<strike>, où je vous tue.</strike></p>
<h3>Doudounotte</h3>
<p>Microsoft propose une guideline relative aux events :</p>
<blockquote><p>&#8230;the delegate type used for an event should take two parameters, an &laquo;&nbsp;object source&nbsp;&raquo; parameter indicating the source of the event, and an &laquo;&nbsp;e&nbsp;&raquo; parameter that encapsulates any additional information about the event. The type of the &laquo;&nbsp;e&nbsp;&raquo; parameter should derive from the EventArgs class. For events that do not use any additional information, the .NET Framework has already defined an appropriate delegate type: EventHandler.</p></blockquote>
<p>Ce n&rsquo;est qu&rsquo;un encouragement, hein, vous êtes libre d&rsquo;avoir des events de type <code>Action&lt;Func&lt;Dictionary&lt;string, List&lt;uint&gt;&gt;, Guid&gt;, bool&gt;</code> si vous le souhaitez. Néanmoins, l&rsquo;idée est louable, puisque si le conseil est suivi, la contravariance permettrait à la méthode suivante de devenir un handler universel :</p>
<pre class="brush: csharp; title: ; notranslate">
public void OnEvent(object sender, EventArgs e)
{
}
</pre>
<p>Je suppose que c&rsquo;est l&rsquo;ambition très secrète de toutes les méthodes du monde. En tout cas, si j&rsquo;étais une méthode, l&rsquo;idée me séduirait.</p>
<h3>Synchronisation</h3>
<p>Pour les events, lorsqu&rsquo;on laisse le compilateur générer le backing field et les accesseurs, ces derniers seront automatiquement synchronisés. Le compilateur associera en effet l&rsquo;attribut <code>MethodImpl</code> avec l&rsquo;option <code>MethodImplOptions.Synchronized</code> aux méthodes <code>add</code> et <code>remove</code>, ce qui est fonctionnellement équivalent à prendre un lock sur l&rsquo;instance ou le type, selon si l&rsquo;event est ou non statique.</p>
<p>Par contre, si vous préférez fournir votre propre implémentation pour les accesseurs, ce sera à vous de prévoir la synchronisation en utilisant un lock manuellement, si nécessaire.</p>
<p><em>Merci <a href="http://patricelamarche.net/">Patrice</a> !</em></p>
<h3>Menteur</h3>
<p>Si un event n&rsquo;est que deux méthodes, comment se fait-il alors, gros malin, que l&rsquo;on puisse écrire et compiler :</p>
<pre class="brush: csharp; title: ; notranslate">
public event EventHandler Click;

public void ICanHazInvokashun()
{
    Click(this, EventArgs.Empty);
}
</pre>
<p>En effet, un évènement est bien invocable. Ca voudrait dire que le compilateur est capable de tricher, et d&rsquo;appeler sournoisement la méthode <code>Invoke</code> sur le champ privé caché ? Et bien oui. Le pseudo IL du corps de <code>ICanHazInvokashun</code> ressemble à :</p>
<pre class="brush: csharp; title: ; notranslate">
ldarg.0 
ldfld class System.EventHandler Button::Click
ldarg.0 
ldsfld class System.EventArgs System.EventArgs::Empty
callvirt instance void System.EventHandler::Invoke(object, class System.EventArgs)
ret
</pre>
<p>A la ligne 2 on constate que c&rsquo;est bien un champ (<code>ldfld</code> = load field) qui est poussé sur la pile et sur lequel on appelle la méthode <code>Invoke</code> (ligne 5). A quoi d&rsquo;autre pouvions-nous nous attendre ?</p>
<p>Si on décide de fournir une implémentation différente pour <code>add</code> et <code>remove</code>, le compilateur ne devrait plus être en mesure de permettre l&rsquo;invocation directe de l&rsquo;évènement avec la même syntaxe :</p>
<pre class="brush: csharp; title: ; notranslate">
public event EventHandler Click
{
    add { /* rien */ } remove { /* pas mieux */ }
}

public void ICanHazInvokashun()
{
    Click(this, EventArgs.Empty); // Haha j't'ai foolé, sale compiler.
}
</pre>
<p>Effectivement, il n&rsquo;est plus possible de compiler la ligne 8, et on obtient le message d&rsquo;erreur généralement réservé aux utilisateurs du type qui expose l&rsquo;évènement :</p>
<blockquote><p>The event &lsquo;Button.Click&rsquo; can only appear on the left hand side of += or -=</p></blockquote>
<p>Voilà. Certes, c&rsquo;était un post un peu facile, et tout ça n&rsquo;est pas très excitant. Mais après tout, qu&rsquo;est-ce qui peut bien être excitant en C# ? On parle d&rsquo;un <em>langage de programmation</em> ! Alors à moins d&rsquo;être un fanboy, etc.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://codingly.com/2009/08/17/tout-ce-que-vous-navez-pas-besoin-de-savoir-au-sujet-du-mot-cle-event/feed/</wfw:commentRss>
			<slash:comments>16</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/b211157a786d649fe89332c92d55cc991f655409b125949b91098bbfddfbca34?s=96&#38;d=https%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">Romain</media:title>
		</media:content>
	</item>
		<item>
		<title>Je ne suis pas Joel Spolsky</title>
		<link>https://codingly.com/2009/08/05/je-ne-suis-pas-joel-spolsky/</link>
					<comments>https://codingly.com/2009/08/05/je-ne-suis-pas-joel-spolsky/#comments</comments>
		
		<dc:creator><![CDATA[Romain Verdier]]></dc:creator>
		<pubDate>Wed, 05 Aug 2009 13:53:01 +0000</pubDate>
				<category><![CDATA[Posts]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[ALT.NET]]></category>
		<guid isPermaLink="false">http://codingly.com/?p=747</guid>

					<description><![CDATA[Je ne sais pas si vous avez remarqué, mais Joel a carrément sauté le requin. Avant, son blog était maintenu, la plupart du temps drôle, et généralement intéressant. Maintenant, il ne poste plus rien, ou très rarement. Pire : souvent il ne poste que pour signaler qu&#8217;il vient d&#8217;écrire un article sur Inc. Du coup [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Je ne sais pas si vous avez remarqué, mais <a href="http://www.joelonsoftware.com/">Joel</a> a carrément <a href="http://en.wikipedia.org/wiki/Jumping_the_shark">sauté le requin</a>. Avant, son blog était maintenu, la plupart du temps drôle, et généralement intéressant. Maintenant, il ne poste plus rien, ou très rarement. Pire : souvent il ne poste que pour signaler qu&rsquo;il vient d&rsquo;écrire un article sur <a href="http://www.inc.com/">Inc.</a> Du coup ses billets ressemblent à <a href="http://www.joelonsoftware.com/items/2009/06/10b.html">ça</a> (sur 8 lignes) :</p>
<blockquote><p>From my latest Inc. column : &laquo;&nbsp;Blah blah blah&nbsp;&raquo;</p></blockquote>
<p>Bon, moi, je ne suis pas Joel Spolsky car je n&rsquo;ai pas tenu 10 ans avant de sauter le requin.<br />
<span id="more-747"></span><br />
Extrait de <a href="http://www.altnetfr.org/2009/08/05/compte-rendu-rencontre-altnet-16-winddbg/">mon dernier compte-rendu sur altnetfr.org</a> :</p>
<blockquote><p>Par contre, Yann ne sait pas coder :</p>
<p><code>for(int i=0; i&lt; 100000000; i++)<br />
{<br />
&nbsp;&nbsp;&nbsp;if(!list.Contains(Guid.NewGuid().ToString()))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;list.Add(Guid.NewGuid().ToString());<br />
}</code></p>
<p>Il faut probablement avoir une maladie mentale pour écrire ça ! C&rsquo;est en tout cas ce que j&rsquo;ai pensé sur le coup, en pouffant sur ma chaise (j’étais au fond de la salle). Ensuite, je ne sais plus si je l&rsquo;ai compris de moi même ou si Yann a dû le préciser d’un air atterré, mais il avait fait exprès d’écrire ça. Parce que d&rsquo;autres ne font pas exprès, et que ça pose des problèmes.</p></blockquote>
<p>C&rsquo;était au sujet de la dernière rencontre ALT.NET parisienne, où <a href="http://blog.polom.com/">Yann Schwartz</a> nous parlait de Windbg et d&rsquo;autres trucs. C&rsquo;était très bien.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://codingly.com/2009/08/05/je-ne-suis-pas-joel-spolsky/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/b211157a786d649fe89332c92d55cc991f655409b125949b91098bbfddfbca34?s=96&#38;d=https%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">Romain</media:title>
		</media:content>
	</item>
		<item>
		<title>ALT.NET en France : Présentation AOP, c&#8217;est fait.</title>
		<link>https://codingly.com/2009/06/18/alt-net-en-france-presentation-aop-cest-fait/</link>
					<comments>https://codingly.com/2009/06/18/alt-net-en-france-presentation-aop-cest-fait/#comments</comments>
		
		<dc:creator><![CDATA[Romain Verdier]]></dc:creator>
		<pubDate>Thu, 18 Jun 2009 08:09:28 +0000</pubDate>
				<category><![CDATA[Posts]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[ALT.NET]]></category>
		<category><![CDATA[AOP]]></category>
		<guid isPermaLink="false">http://codingly.com/?p=716</guid>

					<description><![CDATA[Je me demande si 91 slides valent 1000 mots. Vous pourrez essayer de vous faire une idée puisqu&#8217;elles sont disponibles ci-dessous. Je vous conseille de carrément télécharger la présentation si vous êtes intéressés par les animations, puisque certaines (lire : toutes) sont très logiquement tuées par SlideShare. Bon, pour ma part j&#8217;ai trouvé que ça [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Je me demande si 91 slides valent 1000 mots. Vous pourrez essayer de vous faire une idée puisqu&rsquo;elles sont disponibles ci-dessous. Je vous conseille de carrément télécharger la présentation si vous êtes intéressés par les animations, puisque certaines (lire : toutes) sont très logiquement tuées par SlideShare.</p>
<p>Bon, pour ma part j&rsquo;ai trouvé que ça s&rsquo;était plutôt bien passé considérant que je ne suis pas un speaker &#8211; au mieux un <a href="https://codingly.com/2008/12/29/degage-sale-programmeur/">sale programmeur</a> &#8211; même si j&rsquo;imaginais une présentation un peu plus courte. J&rsquo;ai parlé pendant 45 min, je crois, puis j&rsquo;ai ouvert VS pour la &laquo;&nbsp;démo interactive&nbsp;&raquo; qui s&rsquo;est un peu éternisée.</p>
<p>Je tiens encore à remercier <a href="http://fastconnect.fr/">FastConnect</a> pour la salle, l&rsquo;organisation, le buffet, etc.<br />
<span id="more-716"></span><br />
<iframe src='https://www.slideshare.net/slideshow/embed_code/1601593' width='720' height='590' sandbox="allow-popups allow-scripts allow-same-origin allow-presentation" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe></p>
<p>En ce qui concerne le code des exemples, j&rsquo;essaierai d&rsquo;éditer ce post ultérieurement.</p>
<p><span class="edittag">Edit</span> Quelques liens en rapport :</p>
<ul>
<li><a href="https://codingly.com/2008/10/29/utiliser-laop-avec-postsharp-pour-implementer-inotifypropertychanged/">INotifyPropertyChanged avec PostSharp</a></li>
<li><a href="https://codingly.com/2008/11/10/introduction-a-monocecil-implementer-inotifypropertychanged/">INotifyPropertyChanged avec Mono.Cecil</a></li>
</ul>
<p><span class="edittag">Edit</span> Le <a href="http://www.altnetfr.org/2009/06/24/altnet-paris-14-compte-rendu-aop/">compte rendu de la soirée</a> est maintenant dispo sur le site ALT.NET Fr. Merci <a href="http://evain.net/blog/">Jb</a>.</p>
<p>N&rsquo;hésitez pas à me faire part de vos critiques <em>positives</em>, puisque les autres, constructives ou pas, elles vexent. OK ?</p>
]]></content:encoded>
					
					<wfw:commentRss>https://codingly.com/2009/06/18/alt-net-en-france-presentation-aop-cest-fait/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/b211157a786d649fe89332c92d55cc991f655409b125949b91098bbfddfbca34?s=96&#38;d=https%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">Romain</media:title>
		</media:content>
	</item>
		<item>
		<title>ALT.NET en France : Présentation AOP à Paris le 17 juin</title>
		<link>https://codingly.com/2009/06/02/alt-net-en-france-presentation-aop-a-paris-le-17-juin/</link>
					<comments>https://codingly.com/2009/06/02/alt-net-en-france-presentation-aop-a-paris-le-17-juin/#comments</comments>
		
		<dc:creator><![CDATA[Romain Verdier]]></dc:creator>
		<pubDate>Tue, 02 Jun 2009 21:18:28 +0000</pubDate>
				<category><![CDATA[Posts]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[ALT.NET]]></category>
		<category><![CDATA[Annonce]]></category>
		<category><![CDATA[AOP]]></category>
		<guid isPermaLink="false">http://codingly.com/?p=655</guid>

					<description><![CDATA[Avant toute chose : Non, je ne chercherai pas à justifier le rythme misérable de mes publications sur ce blog. Et non, je ne m&#8217;excuserai pas de tricher lamentablement en postant aujourd&#8217;hui quelque chose d&#8217;aussi, heu, bref. Je voulais vous informer, ou plus probablement vous rappeler, que j&#8217;allais commettre une présentation sur l&#8217;AOP, le 17 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Avant toute chose : Non, je ne chercherai pas à justifier le rythme misérable de mes publications sur ce blog. Et non, je ne m&rsquo;excuserai pas de tricher lamentablement en postant aujourd&rsquo;hui quelque chose d&rsquo;aussi, heu, bref.</p>
<p>Je voulais vous informer, ou plus probablement vous rappeler, que j&rsquo;allais commettre une présentation sur l&rsquo;<a href="http://en.wikipedia.org/wiki/Aspect-oriented_programming">AOP</a>, le 17 juin, à l&rsquo;occasion de la 14ème rencontre ALT.NET Parisienne. Vous trouverez les détails pratiques <a href="http://www.altnetfr.org/2009/05/28/altnet-paris-14-aspect-oriented-programming-aop/">sur notre joli site</a>. Merci à <a href="http://www.fastconnect.fr">FastConnect</a> qui sponsorise l&rsquo;évènement.<br />
<span id="more-655"></span><br />
Il va sans dire que je serais plus à l&rsquo;aise s&rsquo;il n&rsquo;y avait que 3 personnes qui jugeaient bon de se déplacer. Pourtant, je vais m&rsquo;asseoir sur cette considération et vous inviter à venir nombreux. Plusieurs fois au cours des rencontres précédentes nous avons abordé la question de la programmation orientée aspect lors des discussions libres, et il semblerait donc que le sujet rende curieux, à défaut de préoccuper. Peut-être mérite-t-il que nous lui fassions plus de place le temps d&rsquo;une soirée. Je ne sais pas encore exactement quel sera l&rsquo;agenda, mais l&rsquo;idée est de présenter l&rsquo;AOP en tant que concept, de le confronter gentiment aux paradigmes traditionnels, avant de passer plus concrètement à l&rsquo;étude des différentes techniques et outils qui existent en .NET.</p>
<p>D&rsquo;aucuns pourraient penser que le sujet n&rsquo;est pas spécialement ALT.NET.</p>
<p>Ce à quoi je répondrais :</p>
<blockquote><p>Certes, certes&#8230;</p></blockquote>
<p>Enfin. Si on compte uniquement sur Microsoft pour profiter de l&rsquo;AOP on risque assez rapidement de se sentir à l&rsquo;étroit. Il est possible de faire de l&rsquo;AOP sans sortir de la BCL, oui, et il est possible de faire de l&rsquo;AOP <em>un peu plus facilement</em> en débordant sur <a href="http://stackoverflow.com/questions/833729/built-in-aop-in-c-is-it-on-the-way/833919#833919">EntLib</a>. Cependant, les solutions les plus matures et les plus riches pour faire de l&rsquo;AOP en .NET ne sont pas forcément estampillées Microsoft, ce qui risque de conduire l&rsquo;utilisateur averti vers des frameworks plus spécialisés, open-source ou pas. Je veux parler de Castle.DynamicProxy, PostSharp, Linfu, Mono.Cecil, Spring.NET, etc.</p>
<p>Moi, je trouve que ça sent ALT.NET.</p>
<p>Bref, j&rsquo;espère que cette rencontre verra naitre un débat et que nous pourrons collecter quelques retours d&rsquo;expériences, comparer nos approches, bailler, etc. Encore une fois, toutes les infos sont disponibles sur le site <a href="http://www.altnetfr.org/">altnetfr</a>, à <a href="http://www.altnetfr.org/2009/05/28/altnet-paris-14-aspect-oriented-programming-aop/">cette adresse</a>.</p>
<p>Pensez à <a href="http://www.doodle.com/nd4f57ugtsddqk36">vous inscrire</a>, et n&rsquo;hésitez pas à faire passer l&rsquo;info.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://codingly.com/2009/06/02/alt-net-en-france-presentation-aop-a-paris-le-17-juin/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/b211157a786d649fe89332c92d55cc991f655409b125949b91098bbfddfbca34?s=96&#38;d=https%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">Romain</media:title>
		</media:content>
	</item>
		<item>
		<title>Petit rappel sur le Disposing Pattern en C#</title>
		<link>https://codingly.com/2009/04/01/petit-rappel-sur-le-disposing-pattern-en-c/</link>
					<comments>https://codingly.com/2009/04/01/petit-rappel-sur-le-disposing-pattern-en-c/#comments</comments>
		
		<dc:creator><![CDATA[Romain Verdier]]></dc:creator>
		<pubDate>Wed, 01 Apr 2009 09:02:14 +0000</pubDate>
				<category><![CDATA[Posts]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[WTF]]></category>
		<guid isPermaLink="false">http://codingly.com/?p=641</guid>

					<description><![CDATA[Ca fait longtemps que je veux faire ce post, au sujet d&#8217;une question trop souvent négligée : le disposing pattern. On peut voir ça comme un petit rappel, ou un post à classer dans la catégorie &#171;&#160;back to basics&#160;&#187;. En deux mots, il s&#8217;agit de gérer correctement la libération des ressources non-managées, dans un programme [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Ca fait longtemps que je veux faire ce post, au sujet d&rsquo;une question trop souvent négligée : le <em>disposing pattern</em>. On peut voir ça comme un petit rappel, ou un post à classer dans la catégorie &laquo;&nbsp;back to basics&nbsp;&raquo;. En deux mots, il s&rsquo;agit de gérer correctement la libération des ressources non-managées, dans un programme managé.</p>
<blockquote><p><strong>EDIT </strong>: Ce post est un poisson d&rsquo;avril, évidemment. Il vaudrait mieux ne pas utiliser l&rsquo;implémentation du disposing pattern proposée&#8230;</p></blockquote>
<p><span id="more-641"></span></p>
<h3>Quelques rappels</h3>
<p>On parle de code managé en .NET car on fait implicitement référence au garbage collector qui <em>gère automatiquement la mémoire</em>. Il n&rsquo;est pas question de faire un cours sur le GC, mais retenez juste qu&rsquo;il est très intelligent, et qu&rsquo;il est <em>indépendant</em>. Tellement indépendant qu&rsquo;on ne peut pas prévoir quand est-ce qu&rsquo;il va réellement effectuer son recyclage. Par exemple, lorsque vous écrivez :</p>
<pre class="brush: csharp; title: ; notranslate">
public int Add(int a, int b)
{
    Calculator calculator = new Calculator();
    return calculator.Add(a, b);
};
</pre>
<p>Vous créez une nouvelle instance de <code>Calculator</code> qui sera référencée par la variable locale <code>calculator</code>. A la sortie de la méthode, la variable locale n&rsquo;existe plus, et l&rsquo;instance de <code>Calculator</code> n&rsquo;est donc plus référencée. L&rsquo;espace mémoire qu&rsquo;elle occupe peut être récupéré, et le GC le sait. (Notez l&rsquo;assonance.) Il y a un instant j&rsquo;insistais sur l&rsquo;indépendance du garbage collector : s&rsquo;il sait qu&rsquo;il peut libérer une instance, <strong>vous ne savez pas quand il le fera</strong>.</p>
<p>On considère que la collecte des miettes est indéterministe. Vous n&rsquo;avez aucun moyen de savoir précisément quand le calculator que vous avez instancié précédemment sera collecté. Ca ne sera pas forcément à la sortie de la méthode, comme on pourrait naïvement s&rsquo;y attendre ; ça peut être 47 ms ou 47 secondes après (pour caricaturer) et vous devriez même être heureux de ne pas avoir à vous en soucier.</p>
<p>Mais.</p>
<p>Tout n&rsquo;est pas managé. Parfois, vous utilisez à partir d&rsquo;objets managés des ressources non managées. Même si ça peut paraitre évident, il est bon de revenir là dessus. On parle de &laquo;&nbsp;ressource non managée&nbsp;&raquo; dans ce contexte pour décrire une ressource :</p>
<ul>
<li>Dont l&rsquo;allocation est déclenchée à partir de votre code managé.</li>
<li>Qui doit être libérée.</li>
<li>Mais dont le garbage collector n&rsquo;est pas responsable.</li>
</ul>
<p>Les handles de fichiers, les connexions de bases de données, les sockets réseau ou les références COM sont des exemples de ressources non managées.</p>
<h3>Comment implémenter le disposing pattern</h3>
<p>On se base sur l&rsquo;interface <code>IDisposable</code>, et sur les destructeurs de C#. <code>IDisposable</code> expose une méthode <code>Dispose</code>, qui va détruire l&rsquo;objet, et faire en sorte que sa mémoire soit désallouée du heap (et non pas de la pile comme je le vois souvent dans des blogs), surtout si on fait bien appel au mot clé <code>using</code> qui ne sert pas qu&rsquo;à importer des namespaces.</p>
<p>Mais assez de théorie, passons au code. Imaginons la classe C# suivante, et regardons comment elle fait pour libérer le <code>IntPtr</code> qu&rsquo;elle a en variable publique et qui constitue sa variable non managée dangereuse (attention aux memory leaks lol) :</p>
<blockquote><p><strong>EDIT </strong>: Ce post est un poisson d&rsquo;avril, évidemment. Il vaudrait mieux ne pas utiliser l&rsquo;implémentation du disposing pattern proposée&#8230;</p></blockquote>
<pre class="brush: csharp; title: ; notranslate">
public class MaClasseManagée : IDisposable // on implémente IDisposable
{
    private IntPtr m_Ressource_non_managée; // Attention !
	bool disposed = false; // pour savoir si la classe est libérée  

    public MaClasseManagée(IntPtr ptrnonmanagé)
    {
		if(ptrnonmanagé != null)
		{
			m_Ressource_non_managée = ptrnonmanagé; // allocation mémoire non managée
		}
		else // sinon
		{
			if (ptr.Equals(IntPtr.Zero) == true)
            {
                // on désalloue directement la mémoire du pointeur
				m_Ressource_non_managée = IntPtr.Zero
            }
			GC.CancelFullGCNotification(); // pas obligé, mais il vaut mieux
		}
    }

	public void FaireQuelqueChose()
	{
		// ici on utilise la ressource non managée qui a été allouée
		// ...
		// ...
	}

	// destruteur de la class
	~MaClasseManagée()
	{
		// partie un peu tricky : on interdit au CLR de supprimer l&#039;instance
		// courante car ça a déjà été fait dans le Dispose d&#039;IDisposable
		GC.SuppressFinalize(this);
		
		// on s&#039;assure quand même qu&#039;on garde pas de référence vers le pointeur
		m_Ressource_non_managée = IntPtr.Zero;
	}
	
	// methode dispose la plus importante
    public void Dispose()
    {
        if(!disposed)
        {
			// on appelle le garbage collector, et on force la libération de 
			// tous les objets pour être certains de plus référencer des variables
			// non managées depuis C#
			GC.Collect();
			
			disposed = true; // déja disposé
        }
    }
}
</pre>
<p>Notez donc qu&rsquo;il faut bien faire la différence entre le constructeur, le destructeur, et le dispose. Trop souvent les gens oublient l&rsquo;un des trois, et compromettent du coup la sécurité de leur code.</p>
<p>A l&rsquo;utilisation c&rsquo;est simple :</p>
<pre class="brush: csharp; title: ; notranslate">
// mot clé using
using(MaClasseManagée obj = new MaClasseManagée())
{
	// manipuler obj
	obj.FaireQuelqueChose();
} 
// à la sortie du bloc using, le garbage collector est appellé et libère le tas
// des instances de MaClasseManagée persistantes, donc, forcément avec notre
// pattern, des ressources non managées IntPtr aussi
</pre>
<p>Et voilà :)</p>
<p>Je compte faire un article bientôt sur une nouvelle façon d&rsquo;appréhender cette problématique avec l&rsquo;AOP, notamment dans les architectures distribuées où il y a trop de code à écrire pour qu&rsquo;on puisse se permettre de perdre du temps avec ces considérations bas niveau dans un contexte économique délicat (c&rsquo;est la crise !) qui nous force à économiser le temps et l&rsquo;argent sans pour autant arrêter de produire des logiciels de qualité qui donneront satisfaction au client et permettront aux développeurs de ne pas s&rsquo;arracher les cheveux sur des solutions de 50 projets où les autres ont fait n&rsquo;importe quoi et qu&rsquo;il faut quand même livrer coute que coute tant pis pour les nuits blanches (ça serait quand même un comble de ne plus être en mesure de maitriser son métier, ou de devoir arrêter la qualité sous prétexte que c&rsquo;est les chefs de projets qui décident des planning sans rien comprendre de la technique alors que c&rsquo;est la base).</p>
]]></content:encoded>
					
					<wfw:commentRss>https://codingly.com/2009/04/01/petit-rappel-sur-le-disposing-pattern-en-c/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/b211157a786d649fe89332c92d55cc991f655409b125949b91098bbfddfbca34?s=96&#38;d=https%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">Romain</media:title>
		</media:content>
	</item>
		<item>
		<title>Nouveau site pour ALT.NET France</title>
		<link>https://codingly.com/2009/03/02/nouveau-site-pour-altnet-france/</link>
					<comments>https://codingly.com/2009/03/02/nouveau-site-pour-altnet-france/#comments</comments>
		
		<dc:creator><![CDATA[Romain Verdier]]></dc:creator>
		<pubDate>Mon, 02 Mar 2009 10:21:03 +0000</pubDate>
				<category><![CDATA[Posts]]></category>
		<category><![CDATA[ALT.NET]]></category>
		<category><![CDATA[Annonce]]></category>
		<guid isPermaLink="false">http://codingly.com/?p=626</guid>

					<description><![CDATA[Enfin ! Nous avions un groupe de discussion depuis le début, et nous squattions à droite et à gauche lorsqu&#8217;il était nécessaire de communiquer et de s&#8217;organiser, mais depuis quelques jours nous avons notre vrai portail. Un grand merci à Julien pour son travail, et à ceux qui ont commencé à contribuer à l&#8217;élaboration du [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Enfin ! Nous avions un <a href="http://groups.google.com/group/parisaltnet">groupe de discussion</a> depuis le début, et nous squattions à droite et à gauche lorsqu&rsquo;il était nécessaire de communiquer et de s&rsquo;organiser, mais depuis quelques jours nous avons notre vrai portail. Un grand merci à <a href="http://www.thedotnetfrog.fr/">Julien</a> pour son travail, et à ceux qui ont commencé à contribuer à l&rsquo;élaboration du contenu :</p>
<p><strong><a href="http://www.altnetfr.org/"><del datetime="2017-06-24T20:11:12+00:00">www.altnetfr.org</del></a></strong></p>
<p><strong>Update 24/06/2017</strong> : Bon, maintenant, c&rsquo;est un-site-chinois !</p>
<blockquote><p>ALT.Net est un groupe de développeurs .NET passionnés, cherchant à améliorer la façon dont les logiciels sont développés. Nous reconnaissons qu’il n’y a pas de solution unique à un problème mais qu’il y a une multitude d’alternatives pouvant être appliquées dans différentes situations.</p></blockquote>
<p><span id="more-626"></span></p>
<p>Le but était d&rsquo;offrir une façade à la communauté ALT.NET de France. Jusqu&rsquo;alors il fallait être spécialement motivé pour parvenir à comprendre ce qu&rsquo;était ALT.NET, et encore un peu plus pour oser venir aux rencontres. Le nouveau site devrait donc répondre à ces deux besoins, en décrivant le mouvement et ses principes d&rsquo;une part, et en proposant l&rsquo;agenda des différents évènements que nous organisons d&rsquo;autre part.</p>
<p>La dernière réunion a permis à Nicolas Roux et Frédéric Fadel de nous présenter <a href="http://aspectize.com/">Aspectize</a>, et <a href="http://www.altnetfr.org/2009/02/22/altnet-fr-10-aspectize-compte-rendu-par-gauthier/">un compte rendu</a> a déjà été posté par Gauthier. En Mars, <a href="http://www.altnetfr.org/2009/02/20/altnet-paris-11-test-driven-development/">il sera question de TDD</a>, et c&rsquo;est Djamel Zouaoui et Frédéric Schäfer qui animeront la présentation dans les locaux d&rsquo;Octo. Nous comptons continuer de la sorte en annonçant les réunions futures et en proposant des comptes-rendus régulièrement. N&rsquo;hésitez d&rsquo;ailleurs pas à soumettre vos contributions ; un effort collaboratif ne peut qu&rsquo;être profitable.</p>
<p>Pour ceux qui ne sont pas spécialement enclins à rédiger des comptes-rendus ou à proposer des articles, notez qu&rsquo;il existe un <a href="http://wiki.altnetfr.org/doku.php">wiki</a>, qui offre déjà à tous la possibilité de participer sans contrainte particulière à l&rsquo;enrichissement des ressources ALT.NET en français.</p>
<p>Bref, vous êtes chaudement invités à :</p>
<ul>
<li>Ajouter altnetfr.org dans vos readers</li>
<li>Proposer vos comptes-rendus, vos articles, etc.</li>
<li>Venir à la prochaine réunion (et aux autres)</li>
<li>Faire passer le mot au sujet d&rsquo;ALT.NET France !</li>
<ul>
]]></content:encoded>
					
					<wfw:commentRss>https://codingly.com/2009/03/02/nouveau-site-pour-altnet-france/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/b211157a786d649fe89332c92d55cc991f655409b125949b91098bbfddfbca34?s=96&#38;d=https%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">Romain</media:title>
		</media:content>
	</item>
		<item>
		<title>Si les types étaient des animaux, TypedReference serait un ornithorynque</title>
		<link>https://codingly.com/2009/01/15/si-les-types-etaient-des-animaux-typedreference-serait-un-ornithorynque/</link>
					<comments>https://codingly.com/2009/01/15/si-les-types-etaient-des-animaux-typedreference-serait-un-ornithorynque/#comments</comments>
		
		<dc:creator><![CDATA[Romain Verdier]]></dc:creator>
		<pubDate>Thu, 15 Jan 2009 00:08:29 +0000</pubDate>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[CIL]]></category>
		<category><![CDATA[Optimisation]]></category>
		<guid isPermaLink="false">http://codingly.com/?p=535</guid>

					<description><![CDATA[Devinette : C&#8217;est un type valeur, mais on ne peut pas le caster en object. Il est impossible d&#8217;en déclarer des tableaux. On ne peut l&#8217;utiliser que pour typer les paramètres de méthodes et les variables locales. Il existe 4 mots clés non documentés en C# qui lui sont directement reliés, et autant d&#8217;opcodes en [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Devinette : C&rsquo;est un type valeur, mais on ne peut pas le caster en <code>object</code>. Il est impossible d&rsquo;en déclarer des tableaux. On ne peut l&rsquo;utiliser que pour typer les paramètres de méthodes et les variables locales. Il existe 4 mots clés non documentés en C# qui lui sont directement reliés, et autant d&rsquo;opcodes en CIL. Il permet notamment le support des varargs, et exactement 8 personnes dans le monde se sont souciées plus de 5 min de son existence.</p>
<p>Je veux parler, bien évidemment, de <code><a href="http://www.urbandictionary.com/define.php?term=PITA">TypedReference</a></code>. Je vous propose de découvrir ce type à partir d&rsquo;un exemple rigolo.<br />
<span id="more-535"></span></p>
<h3>Méthodes <em>varargs</em> et interopérabilité</h3>
<p>En C#, lorsqu&rsquo;on veut définir une méthode à nombre de paramètres variables, on utilise la syntaxe suivante :</p>
<pre class="brush: csharp; title: ; notranslate">
public static double Average(params int[] values)
{
    double sum = 0;
    foreach (var i in values)
        sum += i;
    return sum / values.Length;
}
</pre>
<p>Notez le mot clé <code>params</code> qui permet l&rsquo;appel de la méthode en passant un tableau en paramètre, ou en listant plus librement les arguments :</p>
<pre class="brush: csharp; title: ; notranslate">
var parameters = new int[]{45, 68, 97, 45};
ManagedClass.Average (parameters)
// ou bien
ManagedClass.Average (45, 68, 97, 45)
</pre>
<p>En <a href="http://en.wikipedia.org/wiki/C%2B%2B/CLI">C++ / CLI</a>, la syntaxe est un peu différente mais le principe est le même :</p>
<pre class="brush: cpp; title: ; notranslate">
double CodinglyInterop::CppCliLibrary::average(... array&lt;int,1&gt; ^values)
{
	double sum = 0;
	for each (int i  in values)
		sum += i;
	return sum/values-&gt;Length;
}
</pre>
<p>C&rsquo;est pareil, en plus moche. On utilise &laquo;&nbsp;<code>...</code>&nbsp;&raquo; au lieu de &laquo;&nbsp;<code>params</code>&laquo;&nbsp;, et l&rsquo;appelant peut passer un tableau ou une liste d&rsquo;arguments :</p>
<pre class="brush: csharp; title: ; notranslate">
var parameters = new int[]{45, 68, 97, 45};
CppCliLibrary.average(parameters)
// ou bien
CppCliLibrary.average(45, 68, 97, 45)
</pre>
<p>Notez que l&rsquo;interopérabilité entre C# et C++/CLI est native : les deux langages sont managés.</p>
<p>Et en C++ pas CLI, qu&rsquo;est-ce que donnent les fonctions à nombre variable d&rsquo;arguments ?</p>
<p>Bah c&rsquo;est encore plus moche, et plus contraignant. Rappelez-vous :</p>
<pre class="brush: cpp; title: ; notranslate">
extern &quot;C&quot; __declspec(dllexport) double average(int n, ...)
{
	double sum = 0;
	va_list args;
	va_start(args, n);
	for(int i=0 ;i &lt; n; i++)
		sum += va_arg(args, int);
	va_end(args);
	return sum/n;
}
</pre>
<p>La principale différence est finalement assez subtile on n&rsquo;utilise pas explicitement un tableau, mais on fournit un pointeur vers le début de la liste d&rsquo;arguments. C&rsquo;est à la méthode de se débrouiller (avec des macros) pour itérer, caster et s&rsquo;arrêter lorsqu&rsquo;il le faut. Généralement, un autre paramètre nommé de la méthode contient les infos nécessaires à cette opération. Dans l&rsquo;exemple précédent, &laquo;&nbsp;<code>n</code>&nbsp;&raquo; est utilisé pour passer directement le nombre d&rsquo;arguments de la liste. Dans <code>printf</code>, c&rsquo;est la <em>format string</em> qui permet à la fonction de savoir combien d&rsquo;arguments elle doit lire.</p>
<p>La question rigolote, puisque nous sommes dans le contexte d&rsquo;un exemple rigolo, est la suivante :</p>
<p>Mais comment appeler les fonctions natives de ce genre depuis C# ? En utilisant <code><a href="http://fr.wikipedia.org/wiki/P/Invoke">pinvoke</a></code>, probablement, mais plus précisément ?</p>
<p>Réponse : En pleurant. On est obligé de déclarer explicitement les imports pour chacune des utilisations que l&rsquo;on va faire de la fonction dans notre code managé. En gros :</p>
<pre class="brush: csharp; title: ; notranslate">
[DllImport (&quot;NativeLibrary.dll&quot;)]
public static extern double average (int n, int i1);

[DllImport (&quot;NativeLibrary.dll&quot;)]
public static extern double average (int n, int i1, int i2);

[DllImport (&quot;NativeLibrary.dll&quot;)]
public static extern double average (int n, int i1, int i2, int i3);

[DllImport (&quot;NativeLibrary.dll&quot;)]
public static extern double average (int n, int i1, int i2, int i3, int i4);

// Etc.
</pre>
<p>What a <a href="http://www.urbandictionary.com/define.php?term=PITA">PITA</a>, comme qui dirait&#8230; Mais c&rsquo;est ici que l&rsquo;ornithorynque nous sauve la vie. Car on peut écrire :</p>
<pre class="brush: csharp; title: ; notranslate">
[DllImport (&quot;NativeLibrary.dll&quot;, CallingConvention = CallingConvention.Cdecl)]
public static extern double average (int n, __arglist );
</pre>
<p>Et appeler la fonction ainsi :</p>
<pre class="brush: csharp; title: ; notranslate">
NativeWrapper.average (4, __arglist (45, 68, 97, 45))
</pre>
<p>Hourra, donc. Mais quel est ce mot clé bizarre, <code>__arglist</code>, qui n&rsquo;est même pas reconnu par Resharper ? Et bien il s&rsquo;agit d&rsquo;un des mots clés <em>non documentés</em> du langage, qui permettent principalement de jouer avec les <code>TypedReference</code>. Pour mieux comprendre ce qui se passe, essayons de réécrire en C# la méthode <code>Average</code>, sans utiliser le mot clé <code>params</code>, et en se reposant donc uniquement sur les &laquo;&nbsp;références typées&nbsp;&raquo;. On s&rsquo;attaquera ensuite à la définition.</p>
<pre class="brush: csharp; title: ; notranslate">
public class ManagedEvil
{
    public static double Average(__arglist)
    {
        double sum = 0;
        int count = 0;
        var iterator = new ArgIterator(__arglist);
        do
        {
            TypedReference typedReference = iterator.GetNextArg();
            sum += __refvalue( typedReference,int);
            count++;
        } while (iterator.GetRemainingCount() &gt; 0);
        return sum / count;
    }
}
</pre>
<p>On note :</p>
<ul>
<li>L&rsquo;apparition du type <code>ArgIterator</code>, dont on crée une instance à partir de la liste d&rsquo;arguments.</li>
<li>L&rsquo;élément courant retourné par l&rsquo;itérateur est une référence typée : <code>TypedReference</code>.</li>
<li>Un nouveau mot clé, <code>__refvalue</code>, permet d&rsquo;extraire la valeur pointée par la référence.</li>
</ul>
<p>Et tout ça compile, tout ça fonctionne, même si l&rsquo;intérêt est limité. </p>
<h3><code>TypedReference</code>, <code>__makeref</code>, <code>__refvalue</code>, <code>__reftype</code></h3>
<p>Arrêtons les expériences pour décortiquer un peu plus sérieusement ce <code>TypedReference</code>. La MSDN définit <strike>très clairement</strike> la <code>TypedReference</code> :</p>
<blockquote><p>Describes objects that contain both a managed pointer to a location and a runtime representation of the type that may be stored at that location.</p></blockquote>
<p>Retenons qu&rsquo;il s&rsquo;agit d&rsquo;une structure contenant : </p>
<ul>
<li>Un pointeur managé vers un espace mémoire</li>
<li>Le type de ce qui est pointé en mémoire</li>
</ul>
<p>Le meilleur endroit pour trouver des infos au sujet de <code>TypedReference</code> est finalement la spécification <a href="http://www.ecma-international.org/publications/standards/Ecma-335.htm">ECMA 335 du CIL</a>. Je vous laisse fouiller, mais sachez que les bases sont notamment posées dans le paragraphe suivant (cf. 8.6.1.3):</p>
<blockquote><p>La signature d&rsquo;une référence typée est en fait représentée en tant que type valeur de base, comme les entiers ou nombres à virgule flottante. Dans la bibliothèque de classes du framework, le type est représenté par <code>System.TypedReference</code>, tandis que dans le langage intermédiaire il est désigné par le mot clé <code>typedref</code>. Ce type doit uniquement être utilisé pour les paramètres et les variables locales. Il ne peut ni être boxé ni être utilisé pour typer un champ, un élément de tableau, ou une valeur de retour de fonction.</p></blockquote>
<p>Pour que je ne puisse jamais justifier l&rsquo;intérêt de cet article, les gens chez Microsoft ont bien fait attention à exposer ce type le moins possible. Il est pourtant assez utilisé en interne, notamment dans <code>System.Array</code>, <code>System.Threading.Interlocked</code>, les services d&rsquo;intérop (<code>InteropServices</code>) ainsi que dans certains overloads cachés utilisant les varargs (<code>String.Concat</code>, <code>Console.WriteLine</code>). A vrai dire, il semblerait que la raison officielle de son existence soit justement le support par le CLR des listes d&rsquo;arguments, comme nous l&rsquo;avons vu plus tôt. Il existe cependant un autre endroit (parmi d&rsquo;autres) où son utilisation peut s&rsquo;avérer intéressante : la réflexion via les <code>FieldInfo</code>. Mais avant d&rsquo;y venir, regardons plutôt comment utiliser, très mécaniquement, <code>TypedReference</code>. On peut soit utiliser les mots clés interdits, soit &#8211; lorsque c&rsquo;est possible &#8211; utiliser les quelques méthodes statiques de la classe <code>TypedReference</code> elle-même.</p>
<p><strong>Création d&rsquo;une référence typée</strong> : <code>__makeref</code></p>
<p>Les références typées peuvent être obtenues pour des variables de n&rsquo;importe quel type (référence ou valeur) à l&rsquo;aide du mot clé <code>__makeref</code>.</p>
<pre class="brush: csharp; title: ; notranslate">
int i = 42;
TypedReference typedReference = __makeref (i);
</pre>
<p>Ce mot clé dont l&rsquo;usage n&rsquo;est pas documenté correspond à l&rsquo;instruction <code>mkrefany</code> en CIL. Le code intermédiaire correspondant à l&rsquo;exemple précédant est le suivant :</p>
<pre class="brush: cpp; title: ; notranslate">
int i = 42;

L_0000: ldc.i4.s 0x2a	/* push sur la pile d'un int32 = 42						*/
L_0002: stloc.0			/* sauvegarde dans la variable locale i					*/

TypedReference typedReference = __makeref(i);

L_0003: ldloca.s i		/* push sur la pile de l'adresse de i					*/
L_0005: mkrefany int32	/* push sur la pile de la référence typée				*/
L_000a: stloc.1			/* sauvegarde dans la variable locale typedReference	*/
</pre>
<p>La méthode statique <code>TypedReference.MakeTypedReference</code> permet aussi de créer des références typées, mais pas directement à partir d&rsquo;une variable. Nous verrons un exemple d&rsquo;utilisation dans la dernière partie de l&rsquo;article.</p>
<p><strong>Récupérer et/ou modifier la valeur</strong> : <code>__refvalue</code></p>
<p>Une fois qu&rsquo;on a une référence typée, il est possible de lire et/ou d&rsquo;écrire la valeur référencée en utilisant le mot clé <code>__refvalue</code>. Il est visuellement assimilable à un appel de fonction à deux paramètres, dont le premier serait la <code>TypedReference</code>, et le second le type de la valeur référencée. En l&rsquo;utilisant à droite d&rsquo;une affectation, on lit la valeur, et en l&rsquo;utilisant à gauche d&rsquo;une affectation, on écrit la valeur. Assez troublant&#8230;</p>
<pre class="brush: csharp; title: ; notranslate">
int i = 42;
TypedReference typedReference = __makeref(i);
int j = __refvalue (typedReference, int);
__refvalue (typedReference, int) = 24;
</pre>
<p>Encore une fois, il est possible de mapper son utilisation avec un opcode spécifique, <code>refanyval</code> :</p>
<pre class="brush: cpp; title: ; notranslate">
int i = 42;
TypedReference typedReference = __makeref(i);

L_0000: ldc.i4.s 0x2a	/* push sur la pile d'un int32 = 42						*/
L_0002: stloc.0			/* sauvegarde dans la variable locale i					*/
L_0003: ldloca.s i		/* push sur la pile de l'adresse de i					*/
L_0005: mkrefany int32	/* push sur la pile de la référence typée				*/
L_000a: stloc.1			/* sauvegarde dans la variable locale typedReference	*/

int j = __refvalue (typedReference, int);

L_000b: ldloc.1			/* push sur la pile de la typedReference				*/
L_000c: refanyval int32 /* push sur la pile de l'adresse de la référence        */
L_0011: ldind.i4		/* déréférencement et push sur la pile de la valeur		*/
L_0012: stloc.2			/* sauvegarde dans la variable locale j					*/

__refvalue (typedReference, int) = 24;

L_0013: ldloc.1			/* push sur la pile de la typedReference				*/
L_0014: refanyval int32 /* push sur la pile de l'adresse de la référence        */ 
L_0019: ldc.i4.s 0x18	/* push sur la pile d'un int32 = 24						*/
L_001b: stind.i4		/* sauvegarde de la valeur à l'adresse de la référence  */
</pre>
<p>La méthode <code>TypedReference.ToObject</code> permet aussi de déréférencer la <code>TypedReference</code> et d&rsquo;obtenir sa valeur, boxée.</p>
<p><strong>Récupérer le type</strong> : <code>__reftype</code></p>
<p>Enfin, il est possible de récupérer l&rsquo;information de type associée à la <code>TypeReference</code>, en utilisant un dernier mot clé <code>__reftype</code>.</p>
<pre class="brush: csharp; title: ; notranslate">
int i = 42;
TypedReference typedReference = __makeref(i);
Type type = __reftype(typedReference);
</pre>
<p>Là encore, on peut faire correspondre <code>__reftype</code> à l&rsquo;opcode <code>refanytype</code> :</p>
<pre class="brush: cpp; title: ; notranslate">
int i = 42;
TypedReference typedReference = __makeref(i);

L_0000: ldc.i4.s 0x2a	/* push sur la pile d'un int32 = 42						*/
L_0002: stloc.0			/* sauvegarde dans la variable locale i					*/
L_0003: ldloca.s i		/* push sur la pile de l'adresse de i					*/
L_0005: mkrefany int32	/* push sur la pile de la référence typée				*/
L_000a: stloc.1			/* sauvegarde dans la variable locale typedReference	*/

Type type = __reftype(typedReference);

L_000b: ldloc.1			/* push sur la pile de la typedReference				*/
L_000c: refanytype		/* push sur la pile du type token de la référence		*/
L_000e: call class Type::GetTypeFromHandle(RuntimeTypeHandle)
L_0013: stloc.2			/* récupération et sauvegarde du Type à partir du token */
</pre>
<p>Notons que la méthode statique <code>TypedReference.GetTargetType</code> est l&rsquo;équivalent autorisé de <code>__reftype</code>, et qu&rsquo;il existe aussi la méthode <code>TypedReference.TargetTypeToken</code> qui retourne le handle du type sous la forme d&rsquo;un <code>RuntimeTypeHandle</code>. La version light, en somme. </p>
<p>Rien de très impressionnant ; d&rsquo;ailleurs vous pouvez retourner sur youtube car la suite n&rsquo;est pas mieux. Mais je persiste !</p>
<h3>Un autre exemple : <code>GetValueDirect</code> et <code>SetValueDirect</code></h3>
<p>Je vous disais tout à l&rsquo;heure que j&rsquo;avais trouvé un exemple d&rsquo;utilisation dans lequel on pouvait faire intervenir les <code>TypedReference</code>. Il s&rsquo;agit de la lecture écriture des champs par réflexion, et plus particulièrement des champs de type valeur. Et encore plus particulièrement lorsqu&rsquo;ils sont imbriqués.</p>
<p>Prenons pour exemple ce modèle simpliste :</p>
<pre class="brush: csharp; title: ; notranslate">
public struct Person
{
	public Address Address;
}

public struct Address
{
	public City City;
}

public struct City
{
	public int ZipCode;
}
</pre>
<p>Il est important de bien noter que <code>Person</code>, <code>Address</code>, <code>City</code> et <code>ZipCode</code> sont des value types. Si on veut inspecter une instance de <code>Person</code> par réflexion, jusqu&rsquo;à lire le <code>ZipCode</code> de son adresse, on va écrire quelque chose comme :</p>
<pre class="brush: csharp; title: ; notranslate">
// On a une instance de Person
var p = new Person();
p.Address.City.ZipCode = 75000;

// On récupère les FieldInfo
var addressField = typeof(Person).GetField(&quot;Address&quot;);
var cityField = typeof(Address).GetField(&quot;City&quot;);
var zipCodeField = typeof(City).GetField(&quot;ZipCode&quot;);

// On chaine les appels à FieldInfo.GetValue pour inspecter la Person
// et lire la valeur du ZipCode
var zipCode =  (int)zipCodeField.GetValue(cityField.GetValue(addressField.GetValue(p)));
</pre>
<p>Ca fonctionne, mais le boxing a tué mon hourra. <code>GetValue</code> prend un <code>object</code> en argument, et retourne un <code>object</code>, alors qu&rsquo;on travaille ici sur des types valeurs&#8230; En lisant la dernière ligne de droite à gauche :</p>
<ul>
<li>p va être boxé pour être passé en paramètre à <code>GetValue</code></li>
<li><code>addressField.GetValue</code> va boxer la valeur du champ <code>Address</code> pour le retourner sous la forme d&rsquo;un <code>object</code></li>
<li><code>cityField.GetValue</code> va boxer la valeur du champ <code>City</code> pour le retourner sous la forme d&rsquo;un <code>object</code></li>
<li><code>zipCodeField.GetValue</code> va boxer la valeur du champ <code>ZipCode</code> pour le retourner sous la forme d&rsquo;un <code>object</code></li>
<li>Le cast en <code>int</code> effectue l&rsquo;ultime et nécessaire unboxing</li>
</ul>
<p>Pas terrible&#8230;</p>
<p>Heureusement, il existe sur <code>FieldInfo</code> la méthode <code>GetValueDirect</code>, qui prend en paramètre une <code>TypedReference</code> !</p>
<p>Si on peut directement récupérer une référence typée sur le <code>ZipCode</code>, on peut éviter quelques emboitages :</p>
<pre class="brush: csharp; title: ; notranslate">
var p = new Person();
p.Address.City.ZipCode = 75000;
FieldInfo zipCodeField = typeof(City).GetField(&quot;ZipCode&quot;);
var zipCode = (int)zipCodeField.GetValueDirect(__makeref (p.Address.City)); 
</pre>
<p>Seulement, on change les contraintes, car la création de la référence typée de cette façon implique alors que l&rsquo;on connaisse <code>Address</code> et <code>City</code> au design time. Qu&rsquo;à cela ne tienne : il existe la méthode statique <code>TypedReference.MakeTypedReference</code> évoquée plus tôt, qui permet de construire une référence typée à partir d&rsquo;une target et d&rsquo;un tableau de <code>FieldInfo</code> correspondant à l&rsquo;inspection désirée de l&rsquo;espace mémoire réservé par <code>p</code> :</p>
<pre class="brush: csharp; title: ; notranslate">
var p = new Person ();
p.Address.City.ZipCode = 75000;
var addressField = typeof (Person).GetField (&quot;Address&quot;);
var cityField = typeof (Address).GetField (&quot;City&quot;);
var zipCodeField = typeof (City).GetField (&quot;ZipCode&quot;);

TypedReference r = TypedReference.MakeTypedReference (p, new[] {addressField, cityField});
var zipCode = (int) zipCodeField.GetValueDirect (r);
</pre>
<p>Dans ce cas précis, les performances mesurées sont environ <strong>4 fois meilleures</strong> en utilisant <code>GetValueDirect</code> à la place de <code>GetValue</code>. Hourra.</p>
<p>Quant à l&rsquo;écriture, nous n&rsquo;avons même pas le luxe du choix, puisque chainer les <code>SetValue</code> ne peut en aucun cas modifier la personne, cette fonction retournant à chaque fois une <em>copie</em> des valeurs&#8230; Il faut donc nécessairement utiliser <code>SetValueDirect</code> et une <code>TypedReference</code>.</p>
<h3>Conclusion</h3>
<p>La conclusion, que je vous dois brève :</p>
<p><strong>Ce qui n&rsquo;est pas documenté ne doit pas être utilisé</strong>. En gros, tout ce qui est lié aux arglists est à oublier. En revanche, la création et la manipulation de <code>TypedReference</code> sans passer par tous les __mots __clés __moches n&rsquo;est pas réprouvée. Notez simplement que <code>TypedReference</code> n&rsquo;est pas <em>CLS Compliant</em>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://codingly.com/2009/01/15/si-les-types-etaient-des-animaux-typedreference-serait-un-ornithorynque/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
		
		<media:content url="https://2.gravatar.com/avatar/b211157a786d649fe89332c92d55cc991f655409b125949b91098bbfddfbca34?s=96&#38;d=https%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">Romain</media:title>
		</media:content>
	</item>
	</channel>
</rss>
