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

  1. #21
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    février 2010
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    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 : 3 612
    Points : 6 069
    Points
    6 069
    Billets dans le blog
    1

    Par défaut

    Sauf si vos données sont très statiques, je vous déconseille de gérer vous-même un cache : donc une collection globale qui garde en mémoire tout ce qui a été déjà chargé une fois, c'est la porte ouverte aux plantages, inconsistances et limitations en termes d'expérience utilisateur.

    En effet, dans une base de données, toute donnée peut être modifiée à n'importe quel moment, y compris à partir d'un outil indépendant du vôtre.

    Pour cette raison, les objets "métier", ceux qui valident la consistance des données notamment, ne doivent travailler qu'avec des données en cours de saisie : dès que l'utilisateur a terminé, il faut les détruire, quitte à les recharger dans 2 minutes si l'utilisateur les redemande.

    Le seul "cache" qu'on peut conserver, c'est pour les listes de référence (pays, type de voie, famille produit, etc.)
    Mais même là, attention : même si ce sont des données qui changent peu, il faut s'assurer de ne pas gêner les utilisateurs le jour où ça change : que se passe-t-il lorsque l'ADV doit saisir une fiche client dans un pays qui n'existe pas ? S'il faut que le commercial redémarre le programme avant de pouvoir saisir une commande dessus, ou attendre 1 heures que le cache soit rechargé automatiquement, tu peux être sûr que tous les clients seront en France dans la base avec le nom du pays ajouté au nom de la ville, ou ce genre de conneries. Il ne faut à aucun moment que les utilisateurs soient gênés par un mécanisme censé leur faciliter la vie : le SGBD gère lui-même du cache, c'est lui qu'il faut utiliser.

    Je travaille aujourd'hui avec plusieurs outils éditeurs de CRM et ERP.
    Comme par enchantement, ce sont ceux qui sont les plus "archaïques" d'un point de vue fonctionnement interne qui sont les plus performants : c'est toujours plus rapide que faire une "vraie" requête SQL qui ramène tout ce dont tu as besoin que d'interroger 2000 fois des collections d'objet en mémoire car on a préféré lire du cache (pas forcément à jour) plutôt que de faire une requête avec jointure SQL en base de données.

    Et je ne parle pas de la mémoire gaspillée par un tel cache...
    On ne jouit bien que de ce qu’on partage.

  2. #22
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    janvier 2019
    Messages
    139
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Aube (Champagne Ardenne)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2019
    Messages : 139
    Points : 58
    Points
    58

    Par défaut

    Je comprends, mais dans ce cas là, il faut à chaque fois recharger toutes les données pour être certains de la consistance ?.

  3. #23
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    février 2010
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    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 : 3 612
    Points : 6 069
    Points
    6 069
    Billets dans le blog
    1

    Par défaut

    Oui et oui.

    Oui, au moment d'enregistrer une donnée en modification (UPDATE) il est conseillé soit d'avoir verrouillé la ligne avant, soit de la recharger pour vérifier que rien n'a été modifié avant de faire la mise à jour.
    En effet, que se passe-t-il si tu annules une commande alors que Régis est en train de la charger dans le camion ?

    Oui, au moment de charger un écran, il faut recharger les données, y compris celles qui était déjà présentes dans l'écran précédent.
    Si tu entres dans le détail d'une commande, que se passe-t-il si entre le moment où tu affiche l'entête et le moment où tu affiche les lignes, une personne a modifié des lignes ?

    Gérer la concurrence des modifications de données est difficile à mettre en place, et source de nombreux bugs informatiques. Il vaut mieux sacrifier quelques centièmes de seconde à chaque action pour vérifier, plutôt que "d'optimiser" et se vautrer comme une merde quand une donnée a été modifiée ailleurs.
    On ne jouit bien que de ce qu’on partage.

  4. #24
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    janvier 2019
    Messages
    139
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Aube (Champagne Ardenne)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2019
    Messages : 139
    Points : 58
    Points
    58

    Par défaut

    Donc finalement qu'on utilise des DTO ou des dataTable ou DataSet pas de grosses différences ?
    En plus avec mes DTOs, ma DAL renvoit une List d'objets et je crée un bindingSource dont la dataSource = List<objet>
    Mais je ne peux pas utiliser les propriétés de filtrage de la bindingSource alors qu'avec une DataTable je peux...

  5. #25
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    février 2010
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    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 : 3 612
    Points : 6 069
    Points
    6 069
    Billets dans le blog
    1

    Par défaut

    L'avantage des objets de données, c'est qu'on peut les lier entre eux, et y effectuer un certain nombre d'automatismes/contrôles de cohérence, qu'il est impossible de faire avec un DataTable.

    Généralement j'essaie de concilier les deux : je crée un type dérivé de List<T> capable d'exposer un DataTable contenant ses données.
    Ainsi, selon les besoins je peux manipuler l'un ou l'autre.
    On ne jouit bien que de ce qu’on partage.

  6. #26
    Membre expérimenté
    Homme Profil pro
    edi
    Inscrit en
    juin 2007
    Messages
    676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : juin 2007
    Messages : 676
    Points : 1 361
    Points
    1 361

    Par défaut

    Citation Envoyé par StringBuilder Voir le message
    Peut-être une déformation de mon parcours professionnel, ou à l'inverse, une déformation liée à l'évolution de l'informatique depuis les années 90...

    Car la première fois où j'ai entendu parler de 3 tiers (ou plus) c'était à la fin des années 90, lorsque la boîte dans laquelle je travaillais faisait des sites webs.

    A l'époque, je n'avais jamais entendu parler de "couches" ou de MVC, qui sont apparus dans mon bagage de connaissance bien plus tard (autour de 10 ans plus tard)...

    Évidement, MVC date de plus tôt, mais fin 90, c'était tout sauf une chose répandue sur les sites web, où MVC est devenu le standard de développement... plus tard dans les années 2000 !
    Ce n'est pas moi qui irai te jeter la pierre, bien souvent les faits d'origine sont rapidement recouvert d'un limon de faits annexes, récits, interprétations, supputation déformations et mensonges si bien qu'on ne sait plus de quoi il était question au départ. Laurent Bossavit présente le monde du développement logiciel comme un société sans Histoire, dans la mesure où rien n'est institutionnalisé pour préserver et partager notre histoire. Même les (rares) musées consacré à l'informatique sont des musées de l'ordinateur, mais pas du logiciel.
    Conférence à l'Agile Tour Lille 2017 :

    Il a fait un petit bouquin sur le sujet (The Leprechauns of Software Engineering) qui témoigne de ses interrogations et de son travail de recherche et montre à quel point on a vite fait de détourner son passé.

  7. #27
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    janvier 2019
    Messages
    139
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Aube (Champagne Ardenne)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2019
    Messages : 139
    Points : 58
    Points
    58

    Par défaut

    Citation Envoyé par StringBuilder Voir le message
    L'avantage des objets de données, c'est qu'on peut les lier entre eux, et y effectuer un certain nombre d'automatismes/contrôles de cohérence, qu'il est impossible de faire avec un DataTable.

    Généralement j'essaie de concilier les deux : je crée un type dérivé de List<T> capable d'exposer un DataTable contenant ses données.
    Ainsi, selon les besoins je peux manipuler l'un ou l'autre.
    Mais donc vos DataGridView expose les DataTables ? Dans mon cas j'avais fait des List<Objet> et des bindingSource mais le problème était de pouvoir trier les DGV sur plusieurs critères.
    Mais en exposant les DataTables, j'ai l'impression d'enfreindre la réelle utilisation des DataTables qui n'est QUE d'exposer des données.
    Dès que je veux récupérer des choses de la DataTable, j'utilise l’événement click et je récupère les données en lisant directement dans les cellules...
    Alors qu'avec un bindingSource et une liste on peut choisir le "Current".
    Si vous aviez un petit exemple de code, pour illustrer votre utilisation des list et des Dt ^^" , sinon je vais continuer d'utiliser les DT maladroitement.

  8. #28
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    février 2010
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    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 : 3 612
    Points : 6 069
    Points
    6 069
    Billets dans le blog
    1

    Par défaut

    Citation Envoyé par LecGaël Voir le message
    Mais en exposant les DataTables, j'ai l'impression d'enfreindre la réelle utilisation des DataTables qui n'est QUE d'exposer des données.
    Absolument pas.
    Un DGV bindé avec un DataTable qui est passé par un CommandBuilder peut faire toutes les opérations de CRUD sans aucune programmation (ou presque).

    En revanche, effectivement, là on n'est plus du tout dans du MVC... On a bien des objets spécialisés, mais plus de séparation des couches.

    Sinon, je parle d'exposer un DT depuis mon List<T> plutôt dans le cas où j'utilise par exemple un contrôle tiers qui n'accepte qu'un DT comme DataSource. C'était par exemple le cas d'un contrôle calendrier (avec expérience utilisateur identique à celui d'Outlook ou GMail).

    Sinon, pour l'exemple de code, pour ce cas précis, ça donne ça : (mais c'est probablement largement améliorable, tout dépend de ce qu'on veut faire avec...)
    Code csharp : 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
     
        public static DataTable GetDataTable(List<Time> times)
        {
            DataTable dt;
            dt = new DataTable();
            dt.Columns.Add("id", typeof(int));
            dt.Columns.Add("parent", typeof(int));
            dt.Columns.Add("start", typeof(DateTime));
            dt.Columns.Add("end", typeof(DateTime));
            dt.Columns.Add("name", typeof(string));
            dt.Columns.Add("color", typeof(string));
     
            foreach (Time time in times)
            {
                DataRow dr = dt.NewRow();
                dr["id"] = time.Id;
                dr["parent"] = time.TicketId;
                dr["start"] = time.Start;
                dr["end"] = time.End;
                dr["name"] = $"{time.Company.Name} - {time.Ticket.Name}";
                dr["color"] = time.Color;
                dt.Rows.Add(dr);
            }
     
            return dt;
        }
    On ne jouit bien que de ce qu’on partage.

  9. #29
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    janvier 2019
    Messages
    139
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Aube (Champagne Ardenne)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2019
    Messages : 139
    Points : 58
    Points
    58

    Par défaut

    Citation Envoyé par StringBuilder Voir le message
    Absolument pas.
    Un DGV bindé avec un DataTable qui est passé par un CommandBuilder peut faire toutes les opérations de CRUD sans aucune programmation (ou presque).

    En revanche, effectivement, là on n'est plus du tout dans du MVC... On a bien des objets spécialisés, mais plus de séparation des couches.

    Sinon, je parle d'exposer un DT depuis mon List<T> plutôt dans le cas où j'utilise par exemple un contrôle tiers qui n'accepte qu'un DT comme DataSource. C'était par exemple le cas d'un contrôle calendrier (avec expérience utilisateur identique à celui d'Outlook ou GMail).

    Sinon, pour l'exemple de code, pour ce cas précis, ça donne ça : (mais c'est probablement largement améliorable, tout dépend de ce qu'on veut faire avec...)
    Dans ce cas là je ne vois pas l'utilité d'avoir une liste d'objets ^^", car si le DataSource du DGV est un dataTable on ne peut plus récupérer l'objet via un .Current ou autre je trouves ça assez perturbant...
    Les DGV acceptent les bindingSource pourtant j'avais une List<Persons>(exemple bidon) qui dérive normalement naturellement de List<T> or quand je voulais faire un SORT de mon bindingSource pour une barre de recherche au dessus du DGV.
    J'ai essayé de creuser la piste du InotifyPropertyChange aussi, mais apparrement les DGV winform ne sont pas compatible avec cette méthode.

  10. #30
    Membre expérimenté
    Homme Profil pro
    edi
    Inscrit en
    juin 2007
    Messages
    676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : juin 2007
    Messages : 676
    Points : 1 361
    Points
    1 361

    Par défaut

    Dans ton cas ce serait plutôt INotifyCollectionChanged que INotifyPropertyChanged, mais je ne suis pas sûr que ce soit pris en charge par les DataGridView. En revanche tu peux regarder du côté de BindingList<T> et BindingSource.

  11. #31
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    janvier 2019
    Messages
    139
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Aube (Champagne Ardenne)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2019
    Messages : 139
    Points : 58
    Points
    58

    Par défaut

    Merci je regardes de ce côté là.

    J'ai actuellement un problème au niveau d'un combobox:
    voici mon 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
    24
    25
    // bindingSourceAjoutPiece est une liste d'objet
    comboAjoutPiece.DataSource = bindingSourceAjoutPiece;
                comboAjoutPiece.DisplayMember = "Nom";
                comboAjoutPiece.ValueMember = "idPiece"; 
     
     
     public class PieceEntity
        {
            public int idPiece { get; set; }
            public string Nom { get; set; }
            public string symbole { get; set; }
            public List<PieceEntity> composition { get; set; }       
            public override string ToString()
            {
                return Nom + " (" + symbole.Substring(0, 1) + "-" + symbole.Substring(1, 3) + "-" + symbole.Substring(3, 7) + ")";
            }
     
        }
    private void comboAjoutPiece_Format(object sender, ListControlConvertEventArgs e)
            {           
                string nom = ((PieceEntity)e.ListItem).Nom;
                string symbole = ((PieceEntity)e.ListItem).symbole;
                e.Value = nom + " (" + symbole.Substring(0, 1) + "-" + symbole.Substring(1, 3) + "-" + symbole.Substring(3, 4) + ")";
                //comboAjoutPiece.DisplayMember = "nom";
            }
    Je voulais que mon combobox affiche les Nom(s) + le symbole dans la droplist j'ai donc manipulé le format, or j'ai des pièces sans nom mais avec un numéro de symbole et l'inverse (Nom sans symbole) et bien maintenant je n'ai pas toutes les pièces dans la liste... est ce qu'il y a une limitation du nombres d'items ?
    Il respecte bien le format mais j'ai des éléments qui manquent...
    Voila je sais que ce topic à dérivé de son sujet initial, une fois ce problème résolu, on pourra l’enterrer

  12. #32
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    février 2010
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    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 : 3 612
    Points : 6 069
    Points
    6 069
    Billets dans le blog
    1

    Par défaut

    Je pencherais pour une anomalie lors du ToString().
    Surprenant que ça ne plante pas.

    Quand il n'y a pas de nom ou symbole, quelle valeur as-tu ? chaine vide ? null ?

    Essaie de gérer "proprement" tous les cas possibles dans ton ToString : quand il n'y a pas de nom, quand il n'y a pas de symbole, quand il n'y a aucun des deux, quand il y a les deux.

    Sinon, juste un truc : évite de faire des concaténations de strings avec des + : ça oblige à créer une dizaine d'instances de chaînes pour faire ces concaténations. Occupation anormale de la mémoire et surconsommation CPU.

    Passe plutôt par un string.Format() ou un StringBuilder, qui seront bien plus performants... au pire, des string.Contact()...

    Hmmmm, je viens de faire un test, et je suis complètement perplexe par le comportement de .NET Core 2.2 !
    Code cashrp : 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
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
     
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Text;
     
    namespace ConcatenationChaine
    {
        public class Exemple
        {
            static readonly string[] NOMS = { "Dupont", "Durant", "Dupuis", "Dulac", "Dupré", "Delatour", "Desbois", "Dubois", "Deschamps" };
            static readonly string[] PRENOMS = { "Alain", "Barbara", "Charlie", "Denis", "Eric", "Fabrice", "Gaston", "Hervé", "Ingrid", "Julien", "Kamel", "Laure", "Marie", "Nicolas", "Oscar", "Paul", "Quentin", "Ralph", "Steeve", "Tom", "Ursule", "Victor", "William", "Yves", "Zoé" };
     
            public static void Run()
            {
                Random rnd = new Random();
                long memory1 = 0;
                long memory2 = 0;
                long memory3 = 0;
                long memory4 = 0;
                long time1 = 0;
                long time2 = 0;
                long time3 = 0;
                long time4 = 0;
     
                Stopwatch sw = new Stopwatch();
     
                Console.Write("Génération des gens...");
                sw.Start();
     
                List<Person> personnes = new List<Person>();
     
                for (int i = 0; i < 100; ++i)
                {
                    personnes.Add(new Person() { Nom = NOMS[rnd.Next(NOMS.Length)], Prenom = PRENOMS[rnd.Next(PRENOMS.Length)], Naissance = DateTime.Now.AddDays(-rnd.Next(1000, 36500)) });
                }
     
                sw.Stop();
                Console.WriteLine($"{sw.ElapsedMilliseconds} ms");
     
                for (int j = 1; j < 100; ++j)
                {
                    //Console.WriteLine("Concaténation avec string.Format()...");
                    GC.Collect();
                    long memoryBefore = GC.GetTotalMemory(true);
                    sw.Restart();
     
                    string s;
                    for (int i = 0; i < 100; ++i)
                    {
                        foreach (Person p in personnes)
                        {
                            s = p.ToStringFormat();
                        }
                    }
     
                    sw.Stop();
                    memory1 += GC.GetTotalMemory(false) - memoryBefore;
                    time1 += sw.ElapsedMilliseconds;
                    //Console.WriteLine($"{sw.ElapsedMilliseconds} ms, {GC.GetTotalMemory(false) - memoryBefore} octets");
     
                    //Console.WriteLine("Concaténation avec $\"{}\"...");
                    GC.Collect();
                    memoryBefore = GC.GetTotalMemory(true);
                    sw.Restart();
     
                    for (int i = 0; i < 100; ++i)
                    {
                        foreach (Person p in personnes)
                        {
                            s = p.ToStringFormat2();
                        }
                    }
     
                    sw.Stop();
                    memory2 += GC.GetTotalMemory(false) - memoryBefore;
                    time2 += sw.ElapsedMilliseconds;
                    //Console.WriteLine($"{sw.ElapsedMilliseconds} ms, {GC.GetTotalMemory(false) - memoryBefore} octets");
     
                    //Console.WriteLine("Concaténation avec un StringBuilder...");
                    GC.Collect();
                    memoryBefore = GC.GetTotalMemory(true);
                    sw.Restart();
     
                    for (int i = 0; i < 100; ++i)
                    {
                        foreach (Person p in personnes)
                        {
                            s = p.ToStringStringBuilder();
                        }
                    }
     
                    sw.Stop();
                    memory3 += GC.GetTotalMemory(false) - memoryBefore;
                    time3 += sw.ElapsedMilliseconds;
                    //Console.WriteLine($"{sw.ElapsedMilliseconds} ms, {GC.GetTotalMemory(false) - memoryBefore} octets");
     
                    //Console.WriteLine("Concaténation avec des +...");
                    GC.Collect();
                    memoryBefore = GC.GetTotalMemory(true);
                    sw.Restart();
     
                    for (int i = 0; i < 300; ++i)
                    {
                        foreach (Person p in personnes)
                        {
                            s = p.ToStringPlus();
                        }
                    }
     
                    sw.Stop();
                    memory4 += GC.GetTotalMemory(false) - memoryBefore;
                    time4 += sw.ElapsedMilliseconds;
                    //Console.WriteLine($"{sw.ElapsedMilliseconds} ms, {GC.GetTotalMemory(false) - memoryBefore} octets");
                }
     
                Console.WriteLine($"string.Format() {time1 / 100} ms, {memory1 / 100} octets");
                Console.WriteLine($"$\"{{}}\"           {time2 / 100} ms, {memory2 / 100} octets");
                Console.WriteLine($"StringBuilder   {time3 / 100} ms, {memory3 / 100} octets");
                Console.WriteLine($"+               {time4 / 100} ms, {memory4 / 100} octets");
            }
        }
     
        class Person
        {
            public string Nom { get; set; }
            public string Prenom { get; set; }
            public DateTime Naissance { get; set; }
     
            public int Age
            {
                get
                {
                    int Years = DateTime.Now.Year - Naissance.Year;
                    if (DateTime.Now.DayOfYear < Naissance.DayOfYear)
                    {
                        Years--;
                    }
                    return Years;
                }
            }
     
            public string ToStringPlus()
            {
                return Prenom.Substring(0, 1) + " " + Nom + " (" + Age + ")";
            }
     
            public string ToStringFormat()
            {
                return string.Format("{0} {1} ({2})", Prenom.Substring(0, 1), Nom, Age);
            }
     
            public string ToStringFormat2()
            {
                return $"{Prenom.Substring(0, 1)} {Nom} ({Age})";
            }
     
            public string ToStringStringBuilder()
            {
                StringBuilder sb = new StringBuilder();
                sb.Append(Prenom.Substring(0, 1));
                sb.Append(' ');
                sb.Append(Nom);
                sb.Append(" (");
                sb.Append(Age);
                sb.Append(')');
                return sb.ToString();
            }
        }
    }

    Génération des gens...2 ms
    string.Format() 57 ms, 10091685 octets
    $"{}" 17 ms, 3380183 octets
    StringBuilder 14 ms, 5756108 octets
    + 15 ms, 8646410 octets
    On a donc le "+" qui n'est pas su mal au final, surtout en terme de temps…
    string.Format() qui est une catastrophe…
    Et $"{}" qui n'est qu'une simplification d'écriture de string.Format… qui est bien mieu !

    Mais bon, j'ai pas dit que des conneries : StringBuilder est le mieux en termes de temps… mais $"{}" le moins consommateur en mémoire...
    On ne jouit bien que de ce qu’on partage.

  13. #33
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    janvier 2019
    Messages
    139
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Aube (Champagne Ardenne)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Industrie

    Informations forums :
    Inscription : janvier 2019
    Messages : 139
    Points : 58
    Points
    58

    Par défaut

    Bonjour ,

    On a donc le "+" qui n'est pas su mal au final, surtout en terme de temps…
    string.Format() qui est une catastrophe…
    Et $"{}" qui n'est qu'une simplification d'écriture de string.Format… qui est bien mieu !

    Mais bon, j'ai pas dit que des conneries : StringBuilder est le mieux en termes de temps… mais $"{}" le moins consommateur en mémoire...
    [/QUOTE]

    Dacc merci pour le test je vais donc retenir le StringBuilder pour la consommation en mémoire...

    Pour ce qui est de ma méthode ToString(); c'est bizarre, je l'ai modifié pour qu'elle affiche que les noms, ensuite que les prénoms mais j'ai l'impression qu'elle n'est pas utilisé par le combobox pour l'affichage...
    Il prend un bindingSource qui est relié à une liste<> comme je vous l'ai dit... je continu de chercher ^^"

    Bonne journée

  14. #34
    Membre expérimenté
    Homme Profil pro
    edi
    Inscrit en
    juin 2007
    Messages
    676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : juin 2007
    Messages : 676
    Points : 1 361
    Points
    1 361

    Par défaut

    En réalité le test de performance de StringBuilder passe à côté du problème soulevé par le principe de ne pas utiliser de concaténation brute. Il n'y a pas vraiment d'impact lors de petites concaténations, même nombreuses (l'opérateur standard peut même être plus rapide pour peu qu'il soit pris en charge nativement par VM, considérant en outre le surcoût de l'initialisation du StringBuilder). C'est la stratégie de mise à l'échelle qui problématique, plus spécifiquement lorsque l'on veut créer une grande chaîne en assemblant les chaînes composantes (ex: construire une page web, sauvegarder des résultats dans un fichier...) :

    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
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Hello World!");
     
                const int bigNumber = 100000;
                var stopWatch = new Stopwatch();
     
                var simpleOpeTitle = "Concat simple avec opérateur+";
                Console.WriteLine(simpleOpeTitle + "...");
                stopWatch.Start();
                for (int i = 0; i <= bigNumber; ++i)
                {
                    string s = "Number: " + i;
                }
                stopWatch.Stop();
                var simpleOpe = stopWatch.Elapsed;
                stopWatch.Reset();
                GC.Collect();
     
                var simpleSBTitle = "Concat simple avec StringBuilder";
                Console.WriteLine(simpleSBTitle + "...");
                stopWatch.Start();
                for (int i = 0; i <= bigNumber; ++i)
                {
                    string s = new StringBuilder("Number: ").Append(i).ToString();
                }
                stopWatch.Stop();
                var simpleSB = stopWatch.Elapsed;
                stopWatch.Reset();
                GC.Collect();
     
                var complexeOpeTitle = "Concat complexe avec opérateur+";
                Console.WriteLine(complexeOpeTitle + "...");
                string acc = "0";
                stopWatch.Start();
                for (int i = 1; i <= bigNumber; ++i)
                {
                    acc = acc + ", " + i;
                }
                stopWatch.Stop();
                var complexeOpe = stopWatch.Elapsed;
                stopWatch.Reset();
                GC.Collect();
     
                var complexeSBTitle = "Concat complexe avec StringBuilder";
                Console.WriteLine(complexeSBTitle + "...");
                stopWatch.Start();
                var sb = new StringBuilder("0");
                for (int i = 1; i < bigNumber; ++i)
                {
                    sb.Append(", ").Append(i);
                }
                string result = sb.ToString();
                stopWatch.Stop();
                var complexeSB = stopWatch.Elapsed;
                stopWatch.Reset();
                GC.Collect();
     
                Console.WriteLine("Résultat :");
                Console.WriteLine($"{simpleOpeTitle}: {simpleOpe}");
                Console.WriteLine($"{simpleSBTitle}: {simpleSB}");
                Console.WriteLine($"{complexeOpeTitle}: {complexeOpe}");
                Console.WriteLine($"{complexeSBTitle}: {complexeSB}");
     
                Console.ReadLine();
            }
        }
    Les résultats varient un peu selon les exécutions. Pour la première partie, des fois le StringBuilder est devant, des fois c'est l'opérateur standard ; mais la différence est négligeable, même pour 100 000 traitements. Pour la concaténation complexe on est à plus de 20 secondes avec l'opérateur, contre moins d'un 100ème de seconde pour le StringBuilder. Cela est du au fait que dans le premier cas pour 100 000 éléments il y aura 100 000 concaténations, sur des chaines de plus en plus grandes (le GC doit devenir complètement fou). Dans le second cas le StringBuilder se contente de mettre en réserve les chaînes qui lui sont ajoutées et ce n'est qu'à l'appel du ToString que le résultat sera construit ; à ce stade là il devient possible de réserver d'un coup toute la mémoire nécessaire et de faire ensuite de simples copies mémoires.

  15. #35
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    février 2010
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    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 : 3 612
    Points : 6 069
    Points
    6 069
    Billets dans le blog
    1

    Par défaut

    Ah oui, merci pour la correction de mon test.
    Les résultats me laissaient perplexe !
    On ne jouit bien que de ce qu’on partage.

  16. #36
    Membre expérimenté
    Homme Profil pro
    edi
    Inscrit en
    juin 2007
    Messages
    676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : juin 2007
    Messages : 676
    Points : 1 361
    Points
    1 361

    Par défaut

    C'est le genre de mise en perspective qu'on trouve sur l'ancien blog de Joel Polsky. J'ai d'ailleurs oublié de mettre le lien vers l'article en question (pour les non-anglophobes). La petite blague qui résume le tout :

    This code uses the Shlemiel the painter’s algorithm. Who is Shlemiel? He’s the guy in this joke:

    Shlemiel gets a job as a street painter, painting the dotted lines down the middle of the road. On the first day he takes a can of paint out to the road and finishes 300 yards of the road. “That’s pretty good!” says his boss, “you’re a fast worker!” and pays him a kopeck.

    The next day Shlemiel only gets 150 yards done. “Well, that’s not nearly as good as yesterday, but you’re still a fast worker. 150 yards is respectable,” and pays him a kopeck.

    The next day Shlemiel paints 30 yards of the road. “Only 30!” shouts his boss. “That’s unacceptable! On the first day you did ten times that much work! What’s going on?”

    “I can’t help it,” says Shlemiel. “Every day I get farther and farther away from the paint can!”

Discussions similaires

  1. Architecture n-tier avec mean.js
    Par hannibal_smith dans le forum Général Conception Web
    Réponses: 0
    Dernier message: 23/06/2016, 17h33
  2. Combiner l'architecture 3 tiers avec MVC sous CS
    Par medirama dans le forum ALM
    Réponses: 0
    Dernier message: 24/06/2014, 21h07
  3. Architecture 3-tiers avec Asp.NET
    Par tawaha2010 dans le forum ASP.NET
    Réponses: 4
    Dernier message: 19/05/2012, 21h34
  4. architecture 3-tiers avec swing
    Par Med_Aymen dans le forum AWT/Swing
    Réponses: 4
    Dernier message: 13/03/2010, 20h47
  5. Réponses: 9
    Dernier message: 10/03/2008, 09h44

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