IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Commande c# non fonctionnelle, parfois


Sujet :

C#

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    78
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 78
    Par défaut Commande c# non fonctionnelle, parfois
    Bonjour et meilleurs vœux à tout le monde


    Je lance une commande (cmd) comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    private void Bouton_Click(object sender, EventArgs e)
    {
        base.Enabled = false;
            Application.DoEvents();
            string arg = " -p " + textBox1.Text + " -y " + textBox2.Text + " -z " + comboBox1.Text + " -v " + comboBox2.Text + " -j 0 " + label1.Text;
            Process process = new Process
            {
                StartInfo = { Arguments = arg, FileName = Application.StartupPath + "\\action.exe", CreateNoWindow = true, UseShellExecute = false }
            };
            process.Start();
            process.WaitForExit();
            MessageBox.Show("Ok !");
     
     
    }
    Seulement voilà, ça ne fonctionne pas lorsque le chemin possède des espaces.
    J'ai lu ici et là qu'il faudrait mettre des " sur le chemin des arguments mais comment faire car si j'écris ceci ça ne fonctionne pas (forcement ^^) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    string arg = "" -p " + textBox1.Text + " -y " + textBox2.Text + " -z " + comboBox1.Text + " -v " + comboBox2.Text + " -j 0 " + label1.Text;";
    Merci de votre aide.

  2. #2
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 004
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 004
    Par défaut
    Bonjour,

    Il n'existe pas des fonctions de formatage de chaînes de caractères en C#, je sais qu'en python on pourrait utiliser la méthode format ?
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  3. #3
    Expert confirmé
    Homme Profil pro
    Responsable Données
    Inscrit en
    Janvier 2009
    Messages
    5 347
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable Données

    Informations forums :
    Inscription : Janvier 2009
    Messages : 5 347
    Par défaut
    Bonjour,
    Tu peux essayer avec une chaîne interpolée:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    string arg = $" -p \"{textBox1.Text}\" -y \"{textBox2.Text}\" -z \"{comboBox1.Text}\" -v \"{comboBox2.Text}\" -j 0 \"{label1.Text}\";";
    Tatayo.

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    78
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 78
    Par défaut
    Merci pour vos réponses / aides.

    Tatayo : j'ai remplacé par ta ligne mais ça ne fonctionne pas comme précédemment.

  5. #5
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 004
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 004
    Par défaut
    Tatayo : j'ai remplacé par ta ligne mais ça ne fonctionne pas comme précédemment.
    Il vous reste la solution String.Format à moins que vous souhaitiez recevoir une réponse toute faite ?

    Et puis si vous expliqueriez ce que vous voyez et ce que vous attendez, peut-être que la solution de @tatayo pourrait être adapté.
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  6. #6
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    940
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 940
    Par défaut
    Pour compléter la réponse de tatayo, il est possible de combiner l'interpolation de chaîne avec les raw strings pour se passer des caractère d'échappement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    string arg = $""" -p "{textBox1.Text}" -y "{textBox2.Text}" -z "{comboBox1.Text}" -v "{comboBox2.Text}" -j 0 "{label1.Text}";""";
    Une autre options est d'en faire une liste de chaînes et d'entourer de guillemets si besoin, puis de joindre avec des espaces :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    string[] args =
    {
        "-p",
        textBox1.Text,
        "-y",
        textBox2.Text,
        "-z",
        comboBox1.Text,
        "-v",
         comboBox2.Text,
         "-j",
         "0",
         label1.Text,
         ";"
    }
    .Select(s => s.Contains(" ") ? "\"{s}\"" : s)
    .ToArray();
     
    string argString = string.Join(' ', args);

  7. #7
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    940
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 940
    Par défaut
    Citation Envoyé par fred1599 Voir le message
    Il vous reste la solution String.Format à moins que vous souhaitiez recevoir une réponse toute faite ?

    Et puis si vous expliqueriez ce que vous voyez et ce que vous attendez, peut-être que la solution de @tatayo pourrait être adapté.
    Il y a string.Format, mais l'interpolation de chaîne est préférable, c'est l'équivalent des f-string en python :
    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    f"-p {text(textbox1)}"

  8. #8
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 907
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 907
    Par défaut
    Citation Envoyé par Noxen Voir le message
    Il y a string.Format, mais l'interpolation de chaîne est préférable, c'est l'équivalent des f-string en python :
    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    f"-p {text(textbox1)}"
    Préférable, c'est un point de vue.
    C'est plus simple, certes.
    Mais, string.Format() permet d'adapter à la culture (même si cela n'est pas nécessaire dans ce cas précis).

  9. #9
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    940
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 940
    Par défaut
    Citation Envoyé par popo Voir le message
    Préférable, c'est un point de vue.
    C'est plus simple, certes.
    Mais, string.Format() permet d'adapter à la culture (même si cela n'est pas nécessaire dans ce cas précis).
    En fait il y a moyen de faire avec l'interpolation de chaîne :
    https://learn.microsoft.com/en-us/do...-interpolation

    Par ailleurs ce sont des arguments de ligne de commande, donc il n'est vraiment question ici de culture. De mon point de vue c'est surtout plus lisible. De plus il me semble qu'il y a des optimisations faites à la compilation (bien qu'ici ce ne soit pas vraiment un goulot d'étranglement).

  10. #10
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 907
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 907
    Par défaut
    L'exemple que tu montre, utilise String.Create.
    Or, String.Create utilise DefaultInterpolatedStringHandler.ToStringAndClear en interne.
    Ce qui signifie que la chaine est transformée deux : une fois par l'interpolation, et une deuxième fois pour y appliquer la culture.
    Ce n'est pas le cas avec String.Format.

    L'argument de la visibilité n'est valable que pour des exemple simple.
    L'argument de la ligne de commande qui n'a pas besoin de culture est tout simplement faux car les commandes lancées ont généralement besoin que les dates ou les nombres soient passés dans un format (le plus souvent CurrentCulture ou InvariantCulture).

    L'optimisation à la compilation fonctionne sur les chaines fixes, ce qui de fait ne fonctionne pas avec l'interpolation.
    La chaine $"Welcome back dear {customerName} !" ne peux être optimisée à la compilation car elle a une partie variable qui est customerName.
    La chaine "Welcome back dear {0} !" est optimisée à la compilation car elle est fixe.

    Edit :
    En dernier lieu, l'interpolation n'est pas possible dans un fichier de ressources.

  11. #11
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 195
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 195
    Billets dans le blog
    1
    Par défaut
    Bonjour,

    Je ne vois pas le rapport avec les chaînes interpolées...

    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    string arg = " -p \"" + textBox1.Text + "\" -y \"" + textBox2.Text + "\" -z \"" + comboBox1.Text + "\" -v \"" + comboBox2.Text + "\" -j 0 \"" + label1.Text + "\"";

    A noter que faire des + sur des strings, c'est la pire des manières de concaténer une chaîne en termes de vitesse et d'allocation mémoire.

    Il est prévérable d'utiliser : (par ordre du plus performant au moins performant)

    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    StringBuilder sb = new();
    sb.Append(" -p \"");
    sb.Append(textBox1.Text);
    [...]
    sb.Append("\"");
    string arg = sb.ToString()

    Ou éventuellement Ou éventuellement
    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    string args = string.Concat(" -p \"", textBox1.Text, ..., "\"");

    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    string args = string.Format(" -p \"{0}" ...", textBox1.Text, ..., );

    Ou les chaînes interpolées, qui ne sont qu'un maquillage du string.Format()
    On ne jouit bien que de ce qu’on partage.

  12. #12
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    940
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 940
    Par défaut
    Citation Envoyé par popo Voir le message
    L'exemple que tu montre, utilise String.Create.
    Or, String.Create utilise DefaultInterpolatedStringHandler.ToStringAndClear en interne.
    Ce qui signifie que la chaine est transformée deux : une fois par l'interpolation, et une deuxième fois pour y appliquer la culture.
    Ce n'est pas le cas avec String.Format.

    L'argument de la visibilité n'est valable que pour des exemple simple.
    L'argument de la ligne de commande qui n'a pas besoin de culture est tout simplement faux car les commandes lancées ont généralement besoin que les dates ou les nombres soient passés dans un format (le plus souvent CurrentCulture ou InvariantCulture).

    L'optimisation à la compilation fonctionne sur les chaines fixes, ce qui de fait ne fonctionne pas avec l'interpolation.
    La chaine $"Welcome back dear {customerName} !" ne peux être optimisée à la compilation car elle a une partie variable qui est customerName.
    La chaine "Welcome back dear {0} !" est optimisée à la compilation car elle est fixe.

    Edit :
    En dernier lieu, l'interpolation n'est pas possible dans un fichier de ressources.
    Je pense que certaines de ces affirmations méritent d'être nuancées.

    L'optimisation à la compilation fonctionne sur les chaines fixes, ce qui de fait ne fonctionne pas avec l'interpolation.
    La chaine $"Welcome back dear {customerName} !" ne peux être optimisée à la compilation car elle a une partie variable qui est customerName.
    La chaine "Welcome back dear {0} !" est optimisée à la compilation car elle est fixe.
    Mon intuition de départ était que la chaîne interpolée est une élément de la syntaxe C# et que ça faisait probablement l'objet d'une passe du compilateur, comme les foreach qui sont transformés en appel à l'énumérateur (sauf pour les tableau qui deviennent des boucles for). Je supposais que le compilateur avait suffisamment d'informations pour découper la chaîne et la réassembler avec les éléments formatés, avec un StringBuilder ou string.Concat par exemple. Après vérification, il semble que je ne sois pas tombé loin. Le compilateur va réécrire le code en instanciant un DefaultInterpolatedStringHandler et en faisant un Append ou AppendFormatted sur les différentes composantes. En pratique la syntaxe d'interpolation permet au compilateur d'avoir les variables de substitutions et les informations de type de façon statique. Et apparemment il y a aussi des optimisations spécifiques lorsque toutes les variables de substitution sont des types. Si les chaînes interpolées était à une époque du sucre syntaxique pour string.Format, ce n'est plus le cas aujourd'hui.

    À titre de comparaison, avec string.Format, la chaîne qui sert de format est tout à fait ordinaire et ne met pas de correspondance explicite entre les ancres de substitution, leur nombre, leur placement et les variables de substitution. La chaîne format va être parsée à l'exécution, alors que la chaîne interpolée est parsée à la compilation. De plus, celles-ci sont généralement transmises avec des paramètres de type object ou object[], ce qui va nécessiter de l'unboxing au moment de la substitution ; l'exception concerne certaines surcharges qui prennent en paramètre un CompositeFormat et sont génériques.

    L'exemple que tu montre, utilise String.Create.
    Or, String.Create utilise DefaultInterpolatedStringHandler.ToStringAndClear en interne.
    Ce qui signifie que la chaine est transformée deux : une fois par l'interpolation, et une deuxième fois pour y appliquer la culture.
    Ce n'est pas le cas avec String.Format.
    C'est ce qu'on aurait pu croire, mais le second paramètre est un DefaultInterpolatedStringHandler, passé par référence, dans le code il faut donner en argument une chaîne interpolée. Il semble que cette méthode serve de point de repère pour le compilateur. En pratique, il va créer un DefaultInterpolatedStringHandler, en lui passant en argument de constructeur le formatteur fourni à la méthode. Donc en réalité la chaîne finale est créée en une seule passe et non deux.

    L'argument de la visibilité n'est valable que pour des exemple simple.
    Je suppose que sur ce genre de sujet chacun voit midi à sa porte.

    L'argument de la ligne de commande qui n'a pas besoin de culture est tout simplement faux car les commandes lancées ont généralement besoin que les dates ou les nombres soient passés dans un format (le plus souvent CurrentCulture ou InvariantCulture).
    Je n'ai rien à dire sur ce point, n'ayant jamais été confronté à cette situation.

    Edit :
    En dernier lieu, l'interpolation n'est pas possible dans un fichier de ressources.
    Effectivement, je ne vois pas comment il pourrait en être autrement. Et les chaînes formatées gardent leur intérêt pour créer des templates.

    En ce qui concerne la concaténation de chaîne, ça provoque des sueurs froides, mais ce ne sont pas non-plus des loups maléfiques issus des entrailles de l'enfer. En fait, elle peut être plus performante sur des chaînes de petites taille que d'autres approches ; par contre, c'est souvent très moche à la lecture. La vraie limitation est la scalabilité, c'est-à-dire que ça va dramatiquement heurter les performances lorsque l'on doit construire une chaîne longue par passes successives et qu'il faut réécrire une chaîne de grande taille à chaque ajout.

    Petit exemple de code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    using System.Globalization;
     
    int arg0 = new Random().Next();
    double arg1 = 1.3;
    string label2 = ", arg2: ";
    string arg2 = arg0.ToString(CultureInfo.GetCultureInfo("es-ES"));
     
    string concat = "concat -> " + " arg0: " + arg0 + ", arg1: " + arg1 + label2 + arg2 + ", done";
     
    string interpolated = $"interpolated -> arg0: {arg0}, arg1: {arg1}, done";
     
    string created = string.Create(
    	CultureInfo.GetCultureInfo("es-ES"),
    	$"created -> arg0: {arg0}, arg1: {arg1}{label2}{arg2}, done");
     
    string formatted = string.Format(
    	CultureInfo.GetCultureInfo("es-ES"),
    	"formatted -> arg0: {0}, arg1: {1}{2}{3}, done", arg0, arg1, label2, arg2);
     
    Console.WriteLine(formatted);
    Console.WriteLine(interpolated);
    Console.WriteLine(created);
    Console.WriteLine(formatted);
    Le résultat avec ILSpy :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    using System;
    using System.Globalization;
    using System.Runtime.CompilerServices;
     
    private static void <Main>$(string[] args)
    {
    	int arg0 = new Random().Next();
    	double arg1 = 1.3;
    	string label2 = ", arg2: ";
    	string arg2 = arg0.ToString(CultureInfo.GetCultureInfo("es-ES"));
    	string concat = "concat ->  arg0: " + arg0 + ", arg1: " + arg1 + label2 + arg2 + ", done";
    	DefaultInterpolatedStringHandler handler = new DefaultInterpolatedStringHandler(36, 2);
    	handler.AppendLiteral("interpolated -> arg0: ");
    	handler.AppendFormatted(arg0);
    	handler.AppendLiteral(", arg1: ");
    	handler.AppendFormatted(arg1);
    	handler.AppendLiteral(", done");
    	string interpolated = handler.ToStringAndClear();
    	IFormatProvider cultureInfo = CultureInfo.GetCultureInfo("es-ES");
    	handler = new DefaultInterpolatedStringHandler(31, 4, cultureInfo);
    	handler.AppendLiteral("created -> arg0: ");
    	handler.AppendFormatted(arg0);
    	handler.AppendLiteral(", arg1: ");
    	handler.AppendFormatted(arg1);
    	handler.AppendFormatted(label2);
    	handler.AppendFormatted(arg2);
    	handler.AppendLiteral(", done");
    	string created = string.Create(cultureInfo, ref handler);
    	CultureInfo cultureInfo2 = CultureInfo.GetCultureInfo("es-ES");
    	global::<>y__InlineArray4<object> buffer = default(global::<>y__InlineArray4<object>);
    	global::<PrivateImplementationDetails>.InlineArrayElementRef<global::<>y__InlineArray4<object>, object>(ref buffer, 0) = arg0;
    	global::<PrivateImplementationDetails>.InlineArrayElementRef<global::<>y__InlineArray4<object>, object>(ref buffer, 1) = arg1;
    	global::<PrivateImplementationDetails>.InlineArrayElementRef<global::<>y__InlineArray4<object>, object>(ref buffer, 2) = label2;
    	global::<PrivateImplementationDetails>.InlineArrayElementRef<global::<>y__InlineArray4<object>, object>(ref buffer, 3) = arg2;
    	string formatted = string.Format(cultureInfo2, "formatted -> arg0: {0}, arg1: {1}{2}{3}, done", global::<PrivateImplementationDetails>.InlineArrayAsReadOnlySpan<global::<>y__InlineArray4<object>, object>(in buffer, 4));
    	Console.WriteLine(formatted);
    	Console.WriteLine(interpolated);
    	Console.WriteLine(created);
    	Console.WriteLine(formatted);
    }
    À noter que le tableau buffer est apparu lorsque j'ai dépassé 3 arguments et qu'il y a eu un changement de la surcharge appelée.

    Article de blog de Stephen Toub (développeur de l'équipe .Net chez Microsoft) concernant l'interpolation de chaîne :
    https://devblogs.microsoft.com/dotne...DT-MVP-5003978

    Un article trouvé au cours de mes recherches qui fait un benchmark de différentes approches :
    https://www.meziantou.net/performanc...ted-string.htm

  13. #13
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 907
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 907
    Par défaut
    Citation Envoyé par Noxen Voir le message
    La chaîne format va être parsée à l'exécution, alors que la chaîne interpolée est parsée à la compilation
    Une chaîne interpolée contient, par définition, une partie variable (ici customerName).
    Et cette partie variable, à moins d'être elle même une constante ne peux pas être déterminée à la compilation.
    A partir du moment où la valeur de customerName peut uniquement être déterminée lors de l'exécution, le compilateur ne pourra pas optimiser la chaine.

  14. #14
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    940
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 940
    Par défaut
    Ce que tu dis n'a aucun sens. Bien sûr que le résultat de la chaîne interpolée ne sera connu qu'à l'exécution, mais c'est aussi le cas de la chaîne formatée. À la compilation, la chaîne interpolée est remplacée par du code qui crée un builder et assemble les différentes parties, constantes ou variables. Pour la chaîne formatée, seul le template est connu à la compilation, la chaîne finale ne sera créée, elle aussi, qu'à l'exécution, lorsque le template sera parsé et les variables de substitution disponibles. Par ailleurs, cette approche est moins fiable, puisque ce n'est qu'au moment du parsing que l'on saura si suffisamment de variables sont disponibles pour hydrater le template, alors que la chaîne interpolée connait les variables à la compilation et le résultat est construit par simple agrégation.

  15. #15
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 907
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 907
    Par défaut
    Cela n'a pas de sens pour toi parce que, apparemment, tu mélanges deux notions bien distinctes que sont l'optimisation à la compilation et le résultat.

    Demande à ton architecte si une chaîne interpolée est optimisée à la compilation. Il te répondra certainement que ouï, depuis C# 10, à condition que
    toutes les expressions utilisées dans la chaîne interpolée soitent constantes. Je ne vois pas comment l'exprimer plus simplement.

  16. #16
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    940
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 940
    Par défaut
    Qu'est-ce-qui serait plus optimisé avec string.Format par rapport à l'interpolation ?

    Dans le pire des cas, le compilateur pourrait remplacer :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    string firstname = Console.ReadLine();
    string lastname = Console.ReadLine();
    string message = $"Hello {firstname} {lastname} and welcome!";
    par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    string firstname = Console.ReadLine();
    string lastname = Console.ReadLine();
    string message = string.Format("Hello {0} {1} and welcome!", firstname, lastname);
    (et c'était probablement ce qui était fait avant C#10).

  17. #17
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 907
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 907
    Par défaut
    La chaine interpolée va se traduire par la création d'un DefaultInterpolatedStringHandler et des appels aux méthodes AppendLiteral pour les parties fixes et AppendFormatted<T> pour les parties variables.
    Le AppendFormatted implique que l'objet T passé dans la chaine interpolée possède également une méthode AppendFormatted.
    Bref, cela créé un code complexe que le compilateur ne peux pas optimiser.
    Et puisqu'à la compilation, la partie variable ne n'est pas connue, cela implique à qu'à chaque passage en runtime, un nouveau DefaultInterpolatedStringHandler sera créé.
    Le format sera appliqué par l'appel à AppendFormatted<T> en runtime.

    Avec un chaine formatée, la chaine est fixe et n'a pas besoin de la création de tous ces objets.
    Le format sera appliquée par l'appel à string.Format en runtime sur une chaine qui est déjà connue et qui n'a pas besoin d'être crée à chaque fois.

    Citation Envoyé par noxen
    et c'était probablement ce qui était fait avant C#10
    Je t'invite à créer un projet en .Net 8 (donc en C# 12), à déclarer un objet de type DefaultInterpolatedStringHandler et à faire F12 dessus.
    En scrollant un peu, tu verras le commentaire laissé par Microsoft sur la méthode AppendFormatted<T>.

    Je cite :
    #region AppendFormatted
    // Design note:
    // The compiler requires a AppendFormatted overload for anything that might be within an interpolation expression;
    // if it can't find an appropriate overload, for handlers in general it'll simply fail to compile.
    // (For target-typing to string where it uses DefaultInterpolatedStringHandler implicitly, it'll instead fall back to
    // its other mechanisms, e.g. using string.Format. This fallback has the benefit that if we miss a case,
    // interpolated strings will still work, but it has the downside that a developer generally won't know
    // if the fallback is happening and they're paying more.)

  18. #18
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    940
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 940
    Par défaut
    Citation Envoyé par popo Voir le message
    La chaine interpolée va se traduire par la création d'un DefaultInterpolatedStringHandler et des appels aux méthodes AppendLiteral pour les parties fixes et AppendFormatted<T> pour les parties variables.
    Tout à fait, c'est-à-dire que la chaîne interpolée va être parsée à la compilation pour créer les appels de fonction. De son côté, string.Format va créer au runtime un ValueStringBuilder qui va parser le template et va tour à tour copier dans son buffer les parties fixes et remplir les trous ("{0}") avec les paramètres.

    Le AppendFormatted implique que l'objet T passé dans la chaine interpolée possède également une méthode AppendFormatted.
    Non, mais je détaille plus loin.

    Bref, cela créé un code complexe que le compilateur ne peux pas optimiser.
    Je n'ai aucune idée de ce que le compilateur peut faire à ce niveau là.

    Et puisqu'à la compilation, la partie variable ne n'est pas connue, cela implique à qu'à chaque passage en runtime, un nouveau DefaultInterpolatedStringHandler sera créé.
    Le format sera appliqué par l'appel à AppendFormatted<T> en runtime.
    De même, à chaque passage au runtime, string.Format devra refaire tout le processus de parsing et de formatage.

    Avec un chaine formatée, la chaine est fixe et n'a pas besoin de la création de tous ces objets.
    Encore une fois, le template est fixe, mais le résultat doit être recalculé avec toutes les créations d'objet impliquée. Les expressions interpolée vont générer des valeurs, mais c'est du code qui devra de toute façon être exécuté aussi pour fournir les arguments à string.Format.

    Le format sera appliquée par l'appel à string.Format en runtime sur une chaine qui est déjà connue et qui n'a pas besoin d'être crée à chaque fois.
    Même point que ci-dessus. Avec une chaîne interpolée, les littéraux de chaînes sont déjà connus aussi et, de la même manière, il me semble, stockés comme constantes dans l'assembly.

    Je t'invite à créer un projet en .Net 8 (donc en C# 12), à déclarer un objet de type DefaultInterpolatedStringHandler et à faire F12 dessus.
    En scrollant un peu, tu verras le commentaire laissé par Microsoft sur la méthode AppendFormatted<T>.
    J'ai testé avec .Net 9 (C# 13). Je ne sais pas si le code a été modifié entre les deux versions, mais le commentaire que tu mentionnes est toujours présent. En revanche, il n'a pas été compris.

    Ces commentaires ne font pas allusion au comportement des expressions d'interpolation, mais à la conception des handlers. Spécifiquement, un handler peut être invoqué implicitement lorsqu'une méthode en prend un en paramètre et qu'une chaîne interpolée est passée en argument.

    Un handler est techniquement valide s'il respecte les points suivants :
    - le type (ref struct est normalement préféré pour des questions de performance) est marqué de l'attribut [InterpolatedStringHandler] ;
    - pour être instancié par le biais d'une chaîne interpolée, il doit disposer d'un constructeur prenant au minimum en paramètre 2 entiers correspondant respectivement à la taille des littéraux (pas le nombre) et au nombre d'expressions ; plus de paramètres sont possibles ;
    - disposer de méthode pour intégrer tous les éléments légaux de la chaîne interpolée, à savoir AppendLiteral pour les littéraux de chaîne et une surcharge de AppendFormatted pour les expressions.

    Si une méthode n'est pas disponible, il y aura une erreur à la compilation (le compilateur tente d'identifier une méthode qui n'existe pas), ce qui peut être un comportement attendu pour restreindre les expressions autorisées. Il n'est absolument pas nécessaire d'avoir une méthode générique.

    Il est possible de passer des arguments au contructeur d'un handler par le biais de l'attribut [InterpolatedStringHandlerArgument] ; il est même possible de désactiver un handler dans certaines circonstances. En dehors de ça, un handler n'est pas restreint à formatter des chaînes et peut faire ce qu'il veut, y compris cuire des cookies et servir le café pour peu qu'on branche de la domotique dessus. La mécanique sous-jacent sert simplement à créer un contexte de pré-analyse.

    En raison de son intégration avec le framework, DefaultInterpolatedStringHandler est particulier sur deux points. Tout d'abord, il peut être invoqué sur les assignations de chaîne (en variable ou en argument), en sus des call sites classiques, puisque c'est son premier rôle.
    Ensuite, en raison encore de son rôle, l'échec de compilation n'est pas permis, si le compilateur ne peut trouver une surcharge approprié (le seul cas qui me vient est l'ambiguïté de surcharge), le compilateur utilisera implicitement un mécanisme de fallback, comme string.Format ou de la concaténation explicite ; c'est à cela qu'il est fait référence en parlant de surcoût caché (utilisation de ces mécanismes au dépend des performances accrues du DefaultInterpolatedStringHandler).

    En terme de performances, DefaultInterpolatedStringHandler a, sur le papier, plusieurs éléments qui parlent en sa faveur. Tout d'abord, point sur lequel on n'arrive pas à être d'accord, pas de parsing à l'exécution. Ensuite, la disponibilité de méthodes spécialiser. AppendFormatted(string) fait un simple AppendLiteral. AppendFormatted(ReadOnlySpan<char>) permet de copier dans le buffer sans surcoût. Les méthodes génériques permettent d'accueillir des value types sans le surcoût de boxing.

    En comparaison, string.Format parse au runtime. Les paramètres sont passés avec un type object ou object[], qui implique du boxing pour tous les value types (int, double, DateTime sont sans doute aussi fréquents que les string pour ce genre de processus).
    Il existe depuis .Net 8 des surcharges génériques pour jusqu'à 3 paramètres. Celles-ci nécessite un CompositeFormat, créé par une méthode de parsing. Ironiquement, ces surchages utilisent un DefaultInterpolatedStringHandler pour effectuer leur traitement.

    Ceci étant-dit, les différences de performances, s'il y a lieu, sont vraisemblablement négligeables à notre échelle. Sur l'ensemble d'un application, les goulots d'étranglement seront ailleurs. Et il faudra de toute façon passer par string.Format lorsque l'on importe du texte, pour de l'internationalisation, par exemple.

  19. #19
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    940
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 940
    Par défaut
    Pour revenir au sujet initial, est-ce-qu'il y a une vérification des données reçu des TextBox, notamment les chemins de fichier ? Par ailleurs, je pense que le code pourrait être amélioré avec un meilleur nommage, soit des TextBox, soit en passant par des variables intermédiaires plus explicites.

  20. #20
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 907
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 907
    Par défaut
    Encore une fois, tu mélanges ce qui est fait à la compilation et ce qui est fait à l'exécution.

    Petit rappel :
    Depuis le départ, je parle d'optimisation de chaine à la compilation.
    string.Format, c'est une méthode, pas une chaine.
    La présence de string.Format n'a aucun impact sur la manière dont la chaine est traitée à la compilation.

Discussions similaires

  1. Incrementer type text parfois non fonctionnel
    Par fabulon46 dans le forum Général JavaScript
    Réponses: 8
    Dernier message: 08/04/2014, 13h47
  2. commande non fonctionnel
    Par djdidi2010 dans le forum WinDev
    Réponses: 2
    Dernier message: 07/05/2012, 14h47
  3. Ligne de commande non fonctionnelle en VB.NET
    Par CLeBeR dans le forum VB.NET
    Réponses: 4
    Dernier message: 26/04/2012, 00h38
  4. Update non fonctionnel
    Par kissmytoe dans le forum Access
    Réponses: 7
    Dernier message: 07/03/2006, 19h37
  5. [REPORTS] Order BY non fonctionnel
    Par sdiack dans le forum Reports
    Réponses: 2
    Dernier message: 10/02/2006, 19h10

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo