Appel de fonctions sans classe

Résolu
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 - 29 août 2017 à 10:35
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 - 30 août 2017 à 18:34
Bonjour,

Venant tout droit du monde de VB6 et passant enfin au C#, j'avais l'habitude de créer des modules ".bas" comportant des fonctions utilitaires standard que j'utilisais dans toutes mes applis.

L'appel de ces fonctions se faisait de n’importe où dans le code, sans la nécessité de créer une instance de classe, même globale.

Je n'arrive pas à reproduire ce principe en C# : tout doit être encapsulé dans des classes, et même en rendant public la classe et les fonctions, il faut toujours en créer une instance dans la classe qui appelle ces fonctions, avec en plus la nécessité de préciser l'espace de nom de la classe, qui n'est pas le même que celui de la classe principale du projet puisque ce code doit être commun à tous les projets qui l'utilisent.

Je trouve cela très lourd pour des fonctions qui ne stockent aucune variable en interne. Je patauge encore avec les modificateurs d'accès, et j'ose espérer qu'il y a un moyen de remplacer MonEspaceDeNom.MaClasseUtilitaire.MaFonction(x,y,z) par tout simplement MaFonction(x,y,z) où que l'on soit dans le code.

Certes, je pense que l'on peut éviter le MonEspaceDeNom à chaque appel par l'utilisation d'un using, mais je voudrais éviter aussi le new MaClasseUtilitaire. toto= new MaClasseUtilitaire() et le toto.MaFonction(a,b,c) par MaFonction(a,b,c) tout court.

Je rêve éveillé ?
A voir également:

14 réponses

Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
29 août 2017 à 16:17
Bonjour

le C# est un langage tout objet, donc tout s'utilise en tant qu'objet.
Le concept est complètement différent de VB6, par conséquent, il te faut "oublier" ce que tu sais.

Le fait de mettre un using en haut de fichier permet d'avoir accès à tous les objets d'un espace de nom (sauf si cette espace de nom est partagé sur plusieurs assembly et qu'elles ne sont pas toutes référencées dans le projet).

Ceci
MaClasseUtilitaire toto= new MaClasseUtilitaire();
toto.MaFonction(a,b,c);
est la syntaxe de base de tout programme C#.

Ceci
MonEspaceDeNom.MaClasseUtilitaire.MaFonction(x,y,z);
ne fonctionne que si est seulement si MaFonction est static. (Comme Math.Cos() par exemple.

L'idée est qu'un objet regroupe tout le code d'un même "thème", par exemple pour un jeu d'échec, il peut y avoir un objet Pièce, qui sera dérivé en Pion, Tour, Cavalier, Fou, Dame, Roi et chacun sera codé pour reproduire le comportement de la pièce.
Un autre objet Echiquier pourra être chargé d'afficher le fond et les pièces.

Si tu veux éviter de faire des new à tout bout de champ (ce qui est d'ailleurs déconseillé), il te faut trimballer la référence de ton objet dans ton code.

J'ai écrit un article sur le sujet, j'espère qu'il est clair, peut-être que cela pourra t'aider.
http://codes-sources.commentcamarche.net/faq/11239-la-programmation-objet-appliquee-a-net-par-l-exemple-partie-1-sur-3


0
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 2
29 août 2017 à 18:02
Merci pour la réponse, et manifestement mon rêve ne deviendra pas réalité.

Je maitrise à peu près l'instanciation, l'héritage et l'implémentation des interfaces (j'ai fait du C++ il y a très longtemps), et la notion de classe ne m'est pas du tout étrangère car je la pratique depuis plus de 20 ans en Visual Basic.
Autant je trouve le principe essentiel pour des objets instanciables, autant je trouve cela super lourd pour des fonctions utilitaires du style:
public string Left(string what, int len)
{
    return what.substr(0, len);
}

Mais bon, puisqu'il faut en passer par là...
J'ai mis une instance en tête de chaque classe, et je la trimballe dans tout le code de chacune.
Parlez-moi d'optimisation du code...
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
29 août 2017 à 18:37
je la pratique depuis plus de 20 ans en Visual Basic

voila qui est rare.
La majorité des codeurs VB passent complètement à coté de l'objet, quelques uns font des contrôles perso, mais des classes, je n'en ai pas vu beaucoup.

Par contre, je ne vois pas l'intérêt de recoder Left.
string droite = "Ce texte sera coupé au 10eme caractères".SubString(0,10);
est au final moins long à écrire

Mais si vraiment tu préfères avoir directement Left, alors le mieux est d'écrire une méthode d'extension, qui est une méthode qui sera ajoutée à la classe String et que tu utiliseras comme ça
string droite = "Ce texte sera coupé au 10eme caractères".Left(10);



0
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 2
Modifié le 29 août 2017 à 19:01
C'était juste un exemple... Il est certain que j'utilise des fonctions plus complexes, mais déjà en simple, j'avais une fonction de ce genre qui vérifiait la présence d'un slash en fin de chaine et qui l'enlevait dans ce cas. Ca évite bien des erreurs de double slash dans les chemins construits dynamiquement.

J'ai essayé de faire une extension à la classe String (comme ce que je fais en JavaScript avec String.prototype.xyz), de la façon suivante :
public class StringEx : String
{
    string Left(string what)
    {
        return what.Substring(0, what.Length);
    }
}

Mais je me suis fait jeter par l'éditeur qui m'a dit "Dérivation du type sealed 'String' impossible'. Après recherche sur "sealed", je me suis aperçu que la classe String n'était pas héritable.

Alors je demande humblement : "Comment on fait ?"

PS : J'étais considéré comme "l'expert" du VB dans ma boite et j'ai réalisé des applications professionnelles extrêmement complexes avec ce langage si décrié par beaucoup de mes confrères. Dommage que l'environnement de développement ne fonctionne plus sous Windows 7 et ultérieurs. Mais je m'en sers encore un peu dans une machine virtuelle tournant sous XP. C'est aussi la raison pour laquelle, ayant tâté du VB.Net qui m'a beaucoup déçu, je me lance dans le C# (après avoir connu Basic, C, Pascal, C6, C++, VB2 à VB6 et la plupart des langages du web).
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
29 août 2017 à 19:17
Le code que tu montres n'est pas une extension, mais un héritage, et effectivement la classe string n'est pas "héritable", par contre elle est "extensible".

Le lien que je t'ai donné propose un exemple, mais il n'est peut être pas très clair.

Donc pour faire une méthode d'extension, il faut commencer par écrire une classe static et public, je vais simplement l'appeler Extension.

public static class Extension
{
}


Si la classe est static, tous ses membres (méthodes, propriétés, champs, événement, etc...) le sont aussi, dans le cas d'extensions, il n'y a que des méthodes.
Ces méthodes ont une signature spécifique, à savoir
public static type NomDeLaMethode(this type1 Variable1, type2 Variable2, etc..)


type est le type de retour de la méthode.
this est le mot clé de l'extension, le type qui suit est le type qui sera étendu et Variable1 contiendra l'objet appelant, type2 Variable2, etc... de manière classique si nécessaire.

Donc pour Left
public static class Extension
{
    public static string Left(this string Texte, int Longueur)
    {
       return Texte.Substring(0, Longueur);
    }

    //allé Right en prime
    public static string Right(this string Texte, int Longueur)
    {
       return Texte.Substring(Texte.Length - Longueur);
    }

}

0
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 2
29 août 2017 à 19:53
Merci beaucoup pour ces éclaircissement !

Je n'ai pas trouvé la moindre trace du mot "extension" dans mon bouquin de C#6, qui fait pourtant plus de 500 pages... Je n'ai pas trouvé le mot extension non plus dans les trois parties du tuto. Je vais me pencher sur le net pour en savoir un peu plus.

Par contre, il y a un truc qui m'interpelle : On ne précise pas de quelle classe mère celle-ci est l'extension. C'est le simple fait de définir une fonction qui ramène un string que cela étend la classe String ?? Cela voudrait dire que dans la même classe "Extension", on pourrait étendre n'importe quelle classe... ce qui me paraît quand même curieux.

A moins qu'il manque une ligne quelque part ?


Malgré tout, je cherchais au départ à utiliser des fonctions "autonomes", et je vois que ce n'est pas possible. Je vais donc faire avec.
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
29 août 2017 à 20:13
Dans mon article, je n'en parle pas, c'est dans le lien du message 3 ou cela est décrit.

Par contre, il y a un truc qui m'interpelle : On ne précise pas de quelle classe mère celle-ci est l'extension.
, si le fait de mettre this devant le type du premier argument définit à la fois qu'il s'agit d'une extension et le type associé est le type étendu.

Malgré tout, je cherchais au départ à utiliser des fonctions "autonomes", et je vois que ce n'est pas possible.
non, tout est objet, même là
"Ce texte sera coupé au 10eme caractères".SubString(0,10)
le texte dans le code est déjà une instance de string. (Ca marche aussi avec les nombres, mais Intellisense ne sait pas interpréter quand on tape le . si on veut utiliser une méthode ou écrire un nombre décimal).

J'étais pas mauvais en VB6 (pas au point d'écrire des classes, juste des contrôles perso), mais il m'a fallut un bon moment avant de coder correctement en C#.
Mon erreur de base a été de considérer que je savais coder, et pouvais donc me passer de voir les bases du langage. Quand je suis arrivé au pied du mur, et que bon gré mal gré, j'ai pris la peine d'apprendre ces bases, j'ai jeté plus de 6 mois de boulot à la poubelle et tout réécriten 2, 3 semaines mieux (pas aux petits oignons, mais efficace et maintenance) .

Il y a un bon cours pour commencer ici, je ne me souviens plus s'il aborde les extension (c'est arrivé avec la framework 3), mais au moins, il permet de bien cerner le fondement de la framework et du langage.
0
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 2 > Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024
29 août 2017 à 20:32
Merci.
J'ai acheté un bouquin pas trop mal fait même s'il ne parle pas des extension) sur le C#6 et visual studio 2015.
Je n'en suis encore qu'au quart. Il y a beaucoup de notions que je connais, mais aussi beaucoup d'autres à apprendre, et surtout à digérer. Je fais attention à ne pas passer sur ce que je pense connaître pour éviter de rater une notion que j'ignore.
Je ne désespère pas y arriver assez rapidement.

Merci encore, je vais bosser...
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656 > MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022
29 août 2017 à 20:37
En anglais ça s'appelle helper.
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
29 août 2017 à 20:49
Je repense à cette phrase
mais déjà en simple, j'avais une fonction de ce genre qui vérifiait la présence d'un slash en fin de chaine et qui l'enlevait dans ce cas. Ca évite bien des erreurs de double slash dans les chemins construits dynamiquement


Utilise la classe Path du namespace IO (y'a un autre Path en WPF).
string toto = Path.GetDirectoryName(@"C:\temp\");


Ou alors simplement replace
string toto = @"C:\temp\\coucou.txt".Replace(@"\\",@"\");

0
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 2
Modifié le 30 août 2017 à 12:09
La première proposition ne répond pas au cahier des charges de ma fonction. En effet, je dois obtenir C:\temp, que la chaine testée soit c:\temp ou c:\temp\. Le GetDirectoyName me renverrait C:\ dans le premier cas.
La deuxième proposition est en effet efficace lors de l'utilisation du chemin, mais pas dans l'affichage d'un champ affichant le dossier de travail courant : le chemin doit être nettoyé pour être utilisé seul.
Ma vraie fonction fait un test sur le dernier caractère de la chaine. En c#, je pense qu'on peut utiliser Regex, qui n’existait pas en VB (mais que je connais bien en PHP et JavaScript).

Je sais, je suis un peu compliqué et maniaque...

Concernant mes fonctions utilitaires, le framework en contient désormais l'équivalent de la plus grande partie. VB était très pauvre en beaucoup de domaines et des routines complémentaires ainsi que l'appel à l'API Windows étaient souvent nécessaires (j'ai même créé une grosse DLL pour encapsuler toutes les fonctions qui me servaient dans chacun de mes programmes). Mon problème est désormais de découvrir la bonne fonction équivalente dans la jungle des espaces de noms du framework. Ça viendra...
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
30 août 2017 à 13:31
Bonjour

ça marchera très bien avec une Regex, mais ça se fait aussi juste avec Path
            string toto = @"C:\temp\\coucou\";
            //string toto = @"C:\temp\\coucou\hello.txt";
            string ext = Path.GetExtension(toto);
            string res;
            if (ext == "")
                res = Path.GetFullPath(toto);
            else
                res = Path.GetDirectoryName(toto);


Ou encore, en condensé
            string toto = @"C:\temp\\coucou\";
            //string toto = @"C:\temp\\coucou\hello.txt";
            string res = Path.GetExtension(toto) == "" ? Path.GetFullPath(toto):Path.GetDirectoryName(toto);



D'ailleurs, pour construire un chemin sans s'embêter, il y a Path.Combine.
0
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 2
Modifié le 30 août 2017 à 14:12
Oui, mais ça me paraît bien lourd et pas évident au premier coup d'oeil...
Moi, je faisait en VB quelque chose comme ça transposé en C# (mais qui marche dans pratiquement tous les langages) :

public string DeleteLastSlash(string sPath)
{
if(sPath.substr(sPath, sPath.length - 1) == "\\")
return sPath.substr(0, sPath.length - 1);
else
return sPath;
}

Et si mes souvenirs de C sont encore bons, on pourrait écrire pour le test :
if(sPath[sPath.length - 1] == '\\')


J'ai pas tout faux ?

PS : À la fin des années 80, le jeu à la mode dans le monde du langage C était de réaliser du code qui tenait sur une seule ligne, au détriment extrême de la lisibilité. Ça aurait pu donner ça :
public string DeleteLastSlash(string sPath){return sPath[sPath.length-1]=='\\'?sPath.substr(0,sPath.length-1):sPath;}

;-)
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
30 août 2017 à 16:05
Oui ça marche aussi, mais ce que je veux te montrer, c'est que plutôt qu'à chaque "morceau" de chemin tester s'il y'a un slash ou pas, tu peux traiter la chaine complète d'un coup et de multiple façons.
Si tu as 50 répertoires, tu lances 50 fois ton test, moi je te propose un seul traitement.

De plus, en construisant ton chemin judicieusement, il ne devrait même pas en avoir besoin.
Par exemple
string tata = Path.Combine(@"C:\temp", "coucou", "hello");
en récupérant coucou et hello, on fait un replace du slash par rien et ça marche. (Alors oui ça ne marche pas pour C:\temp, mais c'est juste un exemple)

Pour tester la fin d'une chaine tu peux faire ainsi
bool test = "est ce que cette chaine finit par hello".EndsWith("hello");


Pour regarder le dernier caractère d'une chaine tu peux faire ainsi
bool test2 = "est ce que cette chaine finit par o".Last() == 'o';


Il y a souvent de nombreuses façons de faire et généralement celle calquée sur "comment je faisais en VB" est la moins optimisée, tout simplement parce qu'il existe de nouveau outils, souvent plus appropriés ou rapides.

Enfin pour ton PS, y'en a toujours qui jouent à ça mais c'est pas mon trip, ni d'ailleurs l'interêt de l'opérateur ternaire, il affecte une variable d'une valeur ou d'une autre selon une condition, ça remplace effectivement 5 lignes, c'est un peu moins lisible quand on n'est pas habitué, mais surtout c'est autorisé dans une requête Linq contrairement à un if / else.
0
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 2
30 août 2017 à 16:47
Tout cela est très vrai.

Mais dans le cas qui nous occupe le chemin est saisi par l'utilisateur (c'est souvent un chemin réseau, et on doit pouvoir le renseigner hors ligne), et/ou le chemin, après sélection avec une boite FolderBrowseDialog, est affiché dans un champ non verrouillé que l’utilisateur peut modifier. Il y a bien sûr bien d'autres vérifications pour être sûr que le format est correct, mais là je sens bien l'utilisation de Regex et ses méthodes de test et de remplacement, dont je maitrise bien les expressions régulières grâce à mon expérience en PHP. Chacun son truc.

Je suis bien conscient qu'on peut faire beaucoup de choses mieux et plus vite qu'en VB, dont j'ai déjà dit qu'il était très pauvre en fonctionnalités. Le problème c'est que pour utiliser une fonction, il faut connaitre son existence, et la richesse des classes du framework n'aide pas à la maitrise de la chose. J'ai eu le même problème dans mes débuts avec JavaScript, dont la hiérarchie des objets est également très volumineuse (et qui en plus est très mal documentée et dépend du navigateur cible. Vive jQuery !).

Bref, il me faudra un peu de temps pour devenir un expert en C#.
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
30 août 2017 à 16:58
Mais les Regex sont un outils que je plébiscite souvent, et si tu te cantonnes au slash se sera simple, mais si tu veux en plus vérifier les caractères interdits ça va se compliquer.

Connais tu ce site?
0
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 2
30 août 2017 à 17:22
Je pense connaître assez les expressions régulières pour en générer des comme ceci (assez classique) :
((^[a-z0-9])(([a-z0-9_-]+)|(([a-z0-9_-]+)[\.]([a-z0-9_-]+)))[@]([a-z0-9-]+)[\-]?([a-z0-9-]+)[\.](([a-z]+)[\.]?([a-z]+)))

ou encore, un peu plus simple :
^[0-9]{1,2}\/[0-9]{1,2}\/([0-9]{2}|[0-9]{4})$

Sans parler des parenthèses capturantes qui permettent d'extraire les données d'une chaîne bien plus facilement qu'avec l'antique sscanf du C original.

Et puis, il y a des tonnes de sites où l'on trouve des trucs sur le C# et la manière d'arriver à ce qu'on veut.

Mais je propose d'arrêter là cette discussion qui n'a plus rien à voir avec la question initiale.
Merci encore pour les conseils.
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
Modifié le 30 août 2017 à 18:03
Et puis, il y a des tonnes de sites où l'on trouve des trucs sur le C# et la manière d'arriver à ce qu'on veut.
oui, mais le dernier site que je t'ai proposé permets de tester les regex telles qu'elles sont implémentées dans .Net.
Par exemple, il y a des langages ou les captures ne peuvent pas avoir de nom, ou la façon de nommer est différentes.

Effectivement, nous avons digressé, si ton problème initial est résolu, pense à mettre le sujet Résolu, avec le lien dédié sous le titre de la discussion
0
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 2 > Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024
30 août 2017 à 18:34
J'ai mis l'adresse du site des Regex dans mes favoris C#.
J'ai la même chose pour Javascript en local, et en PHP sur un de mes sites perso.

Mon problème initial n'est pas résolu et ne le sera jamais, mais j'ai la réponse à ma question.
@+
0
Rejoignez-nous