Wilfried Woivré & .Net

C# et les méthodes d’extensions

JUIL31

Alors pour ceux qui me connaissent du moins dans le monde du travail, vous savez que je n’aime pas redévelopper la roue à chaque projet.

Depuis la version 3 de C#, le langage s’est doté d’un outil que je trouve très puissant, ce sont les méthodes d’extensions. Le but en 2 lignes c’est de permettre d’ajouter des méthodes à des classes existantes du Framework ou de librairies que vous intégrez dans votre code.

Enfin le mieux est un petit exemple, je pense !

 

Imaginons que pour une sauvegarde quelconque, vous ayez besoin, d’enlevez tous les espaces, et tous les accents d’une chaîne saisie par l’utilisateur.

Bon l’on peut trouver sur Internet très rapidement cette fonction :

/// <summary>
/// Fonction de conversion de chaîne accentué en chaîne sans accent
/// http://www.csharpfr.com/codes/CONVERTIR-CHAINE-CARACTERES-CHAINE-SANS-ACCENT_34235.aspx
/// </summary>
/// <param name="chaine">La chaine à convertir</param>
/// <returns>string</returns>
private string convertirChaineSansAccent(string chaine)
{
    // Déclaration de variables
    string accent = "ÀÁÂÃÄÅàáâãäåÒÓÔÕÖØòóôõöøÈÉÊËèéêëÌÍÎÏìíîïÙÚÛÜùúûüÿÑñÇç";
    string sansAccent = "AAAAAAaaaaaaOOOOOOooooooEEEEeeeeIIIIiiiiUUUUuuuuyNnCc";

    // Conversion des chaines en tableaux de caractères
    char[] tableauSansAccent = sansAccent.ToCharArray();
    char[] tableauAccent = accent.ToCharArray();

    // Pour chaque accent
    for (int i = 0; i < accent.Length; i++)
    {
        // Remplacement de l'accent par son équivalent sans accent dans la chaîne de caractères
        chaine = chaine.Replace(tableauAccent[i].ToString(), tableauSansAccent[i].ToString());
    }

    // Retour du résultat
    return chaine;
}

Donc dans un projet, on peut supposer que l’on met cette classe en statique dans une bibliothèques “Tools” ou quelque chose de ce genre.

Donc pas de problème, on sait que cette méthode existe, maintenant prenons le cas qu’un autre développeur arrive sur le projet et ne connaissent pas l’existence de cette méthode, ce qu’il fait, c’est soit rechercher dans la documentation technique l’implémentation d’une telle méthode, soit il recherche dans le code avant de développer.

Mais depuis cette nouvelle version de C#, qui certes commence à être assez ancienne, les méthodes d’extensions sont apparus, on peut donc changer le code de la façon suivante :

class Program
{
    static void Main(string[] args)
    {
        String sOut;
        String sIn = "ÀÁÂÃÄÅàáâãäåÒÓÔÕÖØòóôõöøÈÉÊËèéêëÌÍÎÏìíîïÙÚÛÜùúûüÿÑñÇç";
        sOut = sIn.convertirChaineSansAccent();

    }
}

public static class StringExtensions
{
    /// <summary>
    /// Fonction de conversion de chaîne accentué en chaîne sans accent
    /// </summary>
    /// <param name="chaine">La chaine à convertir</param>
    /// <returns>string</returns>
    public static string convertirChaineSansAccent(this String chaine)
    {
        // Déclaration de variables
        string accent = "ÀÁÂÃÄÅàáâãäåÒÓÔÕÖØòóôõöøÈÉÊËèéêëÌÍÎÏìíîïÙÚÛÜùúûüÿÑñÇç";
        string sansAccent = "AAAAAAaaaaaaOOOOOOooooooEEEEeeeeIIIIiiiiUUUUuuuuyNnCc";

        // Conversion des chaines en tableaux de caractères
        char[] tableauSansAccent = sansAccent.ToCharArray();
        char[] tableauAccent = accent.ToCharArray();

        // Pour chaque accent
        for (int i = 0; i < accent.Length; i++)
        {
            // Remplacement de l'accent par son équivalent sans accent dans la chaîne de caractères
            chaine = chaine.Replace(tableauAccent[i].ToString(), tableauSansAccent[i].ToString());
        }

        return chaine;
    }
}

Alors analysons les changements apportés, à priori rien au niveau de l’algorithme, aucun changement apparent.

Nous voyons en fait que c’est le prototype de la méthode qui a surtout changé, en effet la méthode est maintenant static, et l’on voit apparaître comme paramètre :

this String chaine

 

En fait c’est grâce à ce paramètre que l’on peut réaliser une méthode d’extensions sur la classe String.

Et les méthodes d’extensions seront visibles directement dans l’intellisense comme vous pouvez le voir :

image

 

Bien entendu, vous voyez cette méthode d’extensions, si vous avez ajouté le bon namespace à votre classe !

Après pour des raisons de facilité d’organisation des méthodes d’extensions de projet, ce que je fais je nomme ma classe StringExtensions pour les méthodes d’extensions de la classe String. De plus, toutes mes méthodes d’extensions sont dans un projet personnel que je garde, je n’ai qu’à ajouter les dll, ou ce projet à d’autres projets plus conséquents afin de pouvoir l’utiliser dans tout mes développements.

Remonter

Générer de l'ASP.Net grâce à des fichiers XML et XSLT

AVRI10

Lors de mon dernier stage, j'ai du trouver un moyen de générer des pages ASP.Net depuis des fichiers XML et XSLT, bon à part que le fait que ce fut une expérience enrichissante pour l'utilisation du XSLT, cette génération fut utile du fait que l'on générait des pages entières de statistiques selon des critères situés à distance. (Enfin bon, bref, c'est du vieux travail ....)

Pour ceux qui ne connaissent pas les fichiers XSLT, ce type de fichier est utilisé pour convertir un fichier XML dans un autre fichier de n'importe quel type. Ce type de fichiers contient des "template" et des boucles principalement, dont voici un exemple ci dessous :

<xsl:for-each select="./LISTITEMS/LISTITEM">

<asp:ListItem value="{@value}">

<xsl:value-of select="current()"></xsl:value-of>

</asp:ListItem>

</xsl:for-each>

Cette boucle permet donc pour chaque élément de cet extrait de XML :

<LISTITEMS>

<LISTITEM value="">Select One</LISTITEM>

<LISTITEM value="1">Architector</LISTITEM>

<LISTITEM value="2">Sr. Developer</LISTITEM>

<LISTITEM value="3">Programmer</LISTITEM>

<LISTITEM value="4">Web Designer</LISTITEM>

</LISTITEMS>

On obtiendrait un résultat de ce type :

<asp:ListItem value="">Select One</asp:ListItem>

<asp:ListItem value="1">Architector</asp:ListItem>

<asp:ListItem value="2">Sr. Developer</asp:ListItem>

<asp:ListItem value="3">Programmer</asp:ListItem>

<asp:ListItem value="4">Designer</asp:ListItem>

Donc voici une démonstration de comment faire en C#


private readonly string XslFile = "TestXML/default.xslt";

private readonly string XmlFile = "TestXML/page.xml";

public Panel ControlHolder;


protected void Page_Load(object sender, EventArgs e)

{

XmlDocument xdoc = new XmlDocument();

xdoc.Load(XmlFile);


XslTransform xsl = new XslTransform();

xsl.Load(XslFile);


XsltArgumentList xslarg = new XsltArgumentList();


StringWriter sw = new StringWriter();

xsl.Transform(xdoc, xslarg, sw);


string result = sw.ToString().Replace("xmlns:asp=\"remove\"", "").Replace("&lt;", "<").Replace("&gt;", ">");

sw.Close();

ControlHolder = new Panel();

form1.Controls.Add(ControlHolder);


Control ctrl = new Control();

ctrl = ControlHolder.Page.ParseControl(result);

ControlHolder.Controls.Add(ctrl);

}

}

Lors du déroulement de cette génération, on peut voir dans la variable "result" cet extrait :

<td valign="top">Title:</td>

<td>

<asp:DropDownList runat="server" ID="TITLE">

<asp:ListItem value="">Select One</asp:ListItem>

<asp:ListItem value="1">Architector</asp:ListItem>

<asp:ListItem value="2">Sr. Developer</asp:ListItem>

<asp:ListItem value="3">Programmer</asp:ListItem>

<asp:ListItem value="4">Web Designer</asp:ListItem>

</asp:DropDownList>

</td>

Et à la fin de la génération on obtient une page de ce type :

alt

Pour des informations sur le XSLT je vous renvoie à de très bons sites, cet article était surtout pour vous montrer très rapidement qu'avec du XML et du XSLT, on peut facilement générer des contrôles serveurs !!

Liens XSLT : XSLT et XSL/FO et Cours XSLT

Voici la solution complète de cet article !

alt

Remonter

C# et les générics

MARS21

Au cours de mes différents développements, j'ai souvent eu besoin d'utiliser des méthodes ou des classes génériques afin de gagner en lisibilité du code, et surtout au niveau du nombre de ligne de code.

Et sur ce sujet on me pose souvent deux questions :

  • Comment donner la valeur null à un type générique, puisque si le type en question n'est pas nullable, on aura une erreur à l'exécution.
  • Comment caster un objet en type T.

Alors déjà pour caster un objet en type T, on ne peut bien entendu ne pas faire : liste.add((T)elt) ;

Ce qu'il faut faire c'est changer le type de l'objet via cette méthode :

liste.Add((T)Convert.ChangeType(elt, typeof(T)));

Maintenant comment donner la valeur null à un objet de type générique, techniquement, on ne peut pas faire ceci, à cause de l'erreur ci-dessous.

alt

En effet, imaginons que T soit de type int, et bien il est « non-nullable ». On peut donc lui assigner une valeur par défaut à la place de le mettre toujours null.

T t = default(T);

En effet dans le cas, ou T est « non-nullable » comme avec un type int, la variable t prendra la valeur 0. Si le type est String, alors t vaudra null.

De plus, ce qui est très utile pour les développeurs lors de la conception de leur programme, on peut rajouter sur les déclarations des méthodes, ou des classes une condition à la généricité.

internal Boolean CheckElement<T>(ref T output) where T : BaseElement

Par exemple dans ce cas, on ne pourra se servir de la fonction CheckElement, si, et seulement si, T dérive de BaseElement (ici une classe abstraite du projet), donc tout autre type d'objets passé à la méthode empêche la compilation, ce qui peut s'avérer utilise si l'on veut par la suite utiliser des méthodes ou des attributs de la classe BaseElement.

Remonter

Entity Framework : Trucs et astuces

MARS21

Un article sur les trucs et astuces avec Entity Framework puisqu'après tout c'est la méthode d'accès aux données que je préfère, donc je vais vous en faire profiter. Dans cet article pas de code source au final, juste divers morceaux de codes et screenshots. Avant la base de données de démos :

Comme vous pouvez le voir, c'est les tables « Orders » et « Order_Details » de la base Northwind. Utilisation des classes partielles : Donc comme vous le savez si vous avez fait du Merise, dans une base de données on ne doit mettre aucunes données calculées. C'est-à-dire que pour une commande, on n'a pas de champ « Total », vu qu'en fait c'est la somme des (prix article * nombre d'exemplaire), c'est donc pour cela que dans notre base de données nous n'avons pas le total. Cependant on peut utiliser les classes partielles pour ajouter cette fonctionnalité à notre code. Pour cela il faut rajouter dans le même namespace que le fichier edmx une classe partielle « Orders ». Voici par exemple un code que l'on pourrait voir : namespace ApplicationConsole1

{ public partial class Orders

{

public decimal Total

{

get { return Order_Details.Sum(n => n.Quantity * n.UnitPrice); }

}

} } Et donc grâce aux classes partielles, nous obtenons :

Voilà j'espère que cette astuce vous fera gagner du temps dans vos prochains développement, en tout cas moi j'en use et en abuse. De plus, les classes partielles sont aussi présentes dans le dbml de Linq To Sql !

Remonter