Dot.Blog

C#, XAML, WinUI, WPF, Android, MAUI, IoT, IA, ChatGPT, Prompt Engineering

Le retour des sous-procédures avec les expressions Lambda...

La syntaxe de C# et son orientation "tout objet" ont définitivement tourné la page de la programmation procédurale. Ce n'est certes pas un mal, bien au contraire, mais au passage nous avons perdu une petite facilité de langages tel que Pascal qui autorisaient la déclaration de procédures à l'intérieur de procédures. Le manque n'est pas cruel mais tout de même... Il semble souvent bien lourd et assez artificiel d'être obligé de créer une méthode private ou internal juste pour rendre un service à une seule méthode. De plus le morceau de code ainsi transformé en méthode, même private ou internal, ne sera encapsulé qu'au niveau de la classe et non de la méthode intéressée, d'où le risque de l'utiliser ailleurs (ce qui change sa statégie d"écriture). Le code sera aussi plus lourd en raison de la nécessité de passer en paramètre tout ce qui sera nécessaire à l'exécution de cette "sous méthode" alors qu'une procédure imbriquée peut référencer les variables de la procédure qui l'abrite.

Bref, l'affaire ne mérite certainement pas de grandes théories, mais il faut avouer que de temps en temps on aimerait bien pouvoir déclarer une petite méthode à l'intérieur d'une autre. Il s'agit là d'appliquer la logique des classes elle-mêmes : il est possible de déclarer une classe dans une autre lorsqu'elle ne sert exclusivement qu'à la première. Pourquoi ne pas retrouver cette possibilité au niveau des méthodes d'une classe ?

Les procédures imbriquées n'existent pas en C#. Cela vous semble une certitude. Avec C# 3.0 ce n'est plus aussi certain...

Les expressions Lambda utilisées comme des procédures imbriquées

Je n'entrerai pas ici dans le détail de la syntaxe des expressions Lambda que j'ai déjà présenté dans un long article sur les nouveautés de C# 3.0, article auquel je renvoie le lecteur s'il en ressent le besoin (Les nouveautés syntaxiques de C# 3.0 et Présentation des différentes facettes de LINQ)

Les procédures imbriquées ne sont rien d'autres que des procédures "normales" mais déclarées à l'intérieur d'autres procédures. En Pascal cela ne peut se faire qu'entre l'entête de la méthode principal et le corps de celle-ci :

Procedure blabla
 Procedure imbrique begin ... end;
begin // blabla
...
end; // blabla

Avec les expressions Lambda de C# 3.0 on retrouve une possibilité sensiblement identique avec plus de souplesse encore puisque la "sous procédure" peut être déclarée n'importe où dans le corps de la "procédure principale".

Exemple

static void Main(string[] args)
{
    // une "fonction" imbriquée (teste si un nombre est impair)
   Func<int, bool> isOdd = i => (i & 1) == 1;
   
// une "procédure" imbriquée (formate et écrit un int à la console)
   Action<int> format = i => Console.WriteLine(i.ToString("000")); 
   
   Console.WriteLine(isOdd(25));
   Console.WriteLine(isOdd(24));

   format(25);
   format(258);
   format(5);
}

La sortie sera :

True
False
025
258
005

Conclusion

La possibilité de déclarer des "sous procédures" est bien pratique, cela permet en général d'éviter les répétitions dans le coprs d'une méthode, donc de diminuer le risque de bug et d'améliorer sensiblement la lecture du code. C# ne supportait pas cette possibilité syntaxique, mais en utilisant les expressions Lambda nous retrouvons la même fonctionnalité...

Pour d'autres astuces, Stay Tuned !

Et pour les paresseux le projet VS 2008 : SubRoutines.zip (4,73 kb)

Un éradicateur de fichiers dupliqués gratuit !

Smarter Duplicate File Finder est un outil gratuit très malin : il permet de localiser les fichiers dupliqués dans une liste de répertoires pouvant se situer éventuellement sur des disques différents.

L'intelligence de SDFF se situe à plusieurs niveaux dont la recherche elle-même. Pour localiser les fichiers dupliqués l'utilisateur dispose de plusieurs méthodes : par le nom (casse indifférente), par le type et la taille, par un code de proximité phonétique sur le nom (4 algorithmes : soundex, metaphone, double metaphone et Daitch-Mokotoff, longueur de clé paramétrable de 2 à 50) ou bien par comparaison des contenus par le biais d'une clé de hash MD5 calculée à la volée.

On peut envoyer la liste des fichiers dans le presse-papiers, les déplacer vers tout répertoire ou bien les envoyer à la corbeille de Windows.

La sélection des fichiers montre aussi de l'intelligence : lorsque SDFF créé la liste des doublons il affecte à chaque groupe un code "groupe de proximité" pour pouvoir les traiter séparément. Il devient ainsi possible en un seul clic de sélectionner, pour le conserver, le plus gros, le plus petit, le plus récent ou le plus vieux fichier de chaque groupe. Il est bien entendu possible de sélectionner les fichiers à garder à la main (chaque fichier dans la liste est précédée d'une case à cocher).

Bref, un outil bien pratique. Il est tellement bien que je l'ai adopté tout de suite pour supprimer les doublons de ma collection de mp3 ou bien supprimer les fichiers dupliqués de dossiers clients copiés sur plusieurs disques. Bon, c'est vrai, j'aurais eu du mal à ne pas l'aimer cet outil puisque c'est moi qui l'ai fait :-)

Développé sous VS 2008 en C# 3.0 et framework 3.5 (que le setup installe si vous ne l'avez pas) et faisant appel à beaucoup de LINQ to Object, SDFF est auto-localisé en français et en anglais (mais on peut le forcer dans une langue par la ligne de commande). Le code source n'est pas distribué pour le moment, je travaille encore dessus.

Pour télécharger l'installeur msi c'est ici : https://www.e-naxos.com/download/SDFF1SetupFR.msi

C'est pas un joli cadeau ça ?

Alors Stay Tuned !

(et n'hésitez pas à me laisser un mot si vous avez des idées d'amélioration)

Une petite capture d'écran pour se faire une idée :

Nota: les mp3 de l'exemple sont tous enregistrés via Screamer dont je vous ai parlé dans mon billet coup de gueule sur le piratage. C'est donc du légal, enregistré à la radio et pas du donwload de la mule. Le résultat est rigoureusement le même, sauf que dans un cas on est un bon gars et dans le second on est passible de poursuites, de prison, d'amende et peut être même d'être fouetté en place publique par le patron d'une major. ça démontre la bêtise de la répression et des lois qui se contredisent. ne piratez pas, enregistrez des radios Internet achetez chez des labels indépendants et n'achetez plus rien aux majors ! 

Un excellent livre sur LINQ : "LINQ in Action"

LINQ (encore ! dirons certains, mais c'est justifié je vous l'assure) est une technologie qui décuple la puissance de C#, encore faut-il bien maîtriser toutes les nouveautés syntaxiques de C# 3.0 (voir mes articles sur ce sujet*) et bien comprendre comment tirer partie du meilleur de LINQ lui-même.

Pour cela rien ne vaut un bon livre. Sur le sujet ils ne sont pas très nombreux et quand on fait un peu le tri, il en reste fort peu qui valent l'achat. Ce n'est pas le cas de "LINQ in action" un excellent bouquin qui utilise une approche très pédagogique pour "monter en puissance" au fur et à mesure de la progression des chapitres. C'est d'ailleurs peut-être aussi parce que les auteurs reprennent justement cette logique que j'applique dans mes propres cours sur LINQ que j'apprécie ce livre.

Il s'agit bien entendu d'un ouvrage en anglais, si vous ne maîtriser pas la langue il faudra hélas passer votre chemin. Les concepts avancés dans le livre peuvent s'avérer suffisament sophistiqués en eux-mêmes sans ajouter la difficulté de décryptage si on n'est pas totalement à l'aise avec la prose d'outre-Atlantique.

Pour acheter le livre au moins cher, je vous conseille l'excellent librairie anglaise The Book Repository qui livre en France et qui applique des tarifs généralement hors concurrence. La page du livre est ici "Linq in Action". L'ouvrage possède aussi son propre site avec le téléchargement des exemples ainsi qu'un forum.

(* Les nouveautés syntaxiques de C# 3.0 et Présentation des différentes facettes de LINQ )

LINQ et Réflexion pour obtenir les valeurs de System.Drawing.Color

LINQ... l'un de mes sujets préférés... Plus je l'utilise, à toutes les sauces, et plus je trouve cette technologie indispensable. Mais foin de propagande, voici encore un exemple qui prouve à quel point LINQ peut servir à tout, facilement.

Le but du jeu : récupérer la définition des couleurs de System.Drawing.Color, en faire un tableau trié par ordre alphabétique.

A la "main" je vous souhaite bien du plaisir... Avec LINQ cela donne la chose suivante :

namespace LinqColor
{
  class Program
  {
     static void Main(string[] args)
    {
       var color_type = typeof(System.Drawing.Color);
       var color_properties = from prop in color_type.GetProperties()
                                     where prop.PropertyType == color_type
                                     orderby prop.Name
                                     select prop;
       
       foreach (var color_property in color_properties)
       {
           var cur_color = (System.Drawing.Color) color_property.GetValue(null, null);
           uint rgb_int = (uint) cur_color.ToArgb() & (0x00ffffff);
           Console.WriteLine(" {0,-20} = ({1,-3},{2,-3},{3,-3}) = 0x{4:X00000000}",
           color_property.Name,
           cur_color.R, cur_color.G, cur_color.B,rgb_int);
       }
    }
  }
}

La sortie écran (console) donne la chose suivante :

Le projet VS 2008 pour les fénéants du clavier : LinqColor.zip (5,43 kb)

C'est pas merveilleux LINQ ?

Bien sûr que si... Alors Stay Tuned !