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 :

Auto-delete items dans une List<>


Sujet :

C#

  1. #1
    Membre confirmé Avatar de istace.emmanuel
    Homme Profil pro
    Senior Full-Stack .Net Developer
    Inscrit en
    Août 2009
    Messages
    125
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Belgique

    Informations professionnelles :
    Activité : Senior Full-Stack .Net Developer
    Secteur : Conseil

    Informations forums :
    Inscription : Août 2009
    Messages : 125
    Par défaut Auto-delete items dans une List<>
    Salut j'ai un petit soucis,

    J'ai une liste d'objet Key qui contiennent chacun un DateTime et une GUID (string).
    Je me base sur le dateTime pour savoir si la key est encore valide le soucis c'est que je cherche un moyen pour que l'item s'auto delete une fois X secondes/minutes/heures passé.

    J'ai regardé du coté des DP mais rien trouvé (mal cherché ?)

    J'ai cependant une solution, mais que je trouve très inélégante. Un bgWorker qui lock la liste, check les items une a une et supprime celle qui doivent l'être.

    Quelqu'un a une idée plus élégante ? ou une DP ?

    Infor@tiquement

  2. #2
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Par défaut
    Je vois pas trop de solution propre la dessus.
    Peut être une classe qui encapsule une List<T>.
    Apres tu surcharges les membres pour qu'a chaque accès à un item il y'ait un nettoyage de la collection

  3. #3
    Membre expérimenté
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Par défaut
    Salut

    Moi en gros j'utiliserais un timer une liste triée sur date a partir des element de ta liste originale (en definissant un compareur)

    Si tu gere bien le tri a partir des insertions dans ta liste, tu ne dois pas reparcourir toute ta liste a chaque intervale du timer

  4. #4
    Membre confirmé Avatar de istace.emmanuel
    Homme Profil pro
    Senior Full-Stack .Net Developer
    Inscrit en
    Août 2009
    Messages
    125
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Belgique

    Informations professionnelles :
    Activité : Senior Full-Stack .Net Developer
    Secteur : Conseil

    Informations forums :
    Inscription : Août 2009
    Messages : 125
    Par défaut
    Alors, j'ai fait un mix des deux en attendant.

    L'avantage de la première solution est que lorsque l'on contacte mon service, le nettoyage ayant été fait, je suis sur que si true est renvoyé, c'est true.
    Alors que sur le timer, si il est exec toute les 10sec par exemple, rien ne me dis que 3sec après une clef ne sera pas devenue invalide, mais considéré valide tout de même étant encore présente dans ma liste.

    Par contre le désavantage de la première est que si pendant 2 heures plus aucune demande n'est effectué, je conserve un (grand?) nombre d'objet en mémoire inutilement.

    J'ai donc pour le moment a chaque insert un clean, à la demande de validation un clean et toutes les X minutes un clean au cas ou il n'y aurais plus eu de request depuis longtemp.

    Chaque méthode me permettant de couvrir les inconvenants de l'autre.

    Par contre je me demandais si, encapsuler un timer dans les objets de ma liste qui lève un event auquel est abonné mon objet parent (celui contenant la list<>) ne serait pas une solution.
    Ainsi ma objet parent serait notifié par les objets de la liste "Hé ho, je suis plus valide, delete moi !"
    Qu'en pensez vous ?

  5. #5
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Voilà l'approche que je choisirais :

    - Créer une interface IExpirable qui expose la date de création de l'objet :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public interface IExpirable
    {
        DateTime CreationDate { get; }
    }
    - Créer une classe héritée de Collection<T>, avec une contrainte sur T pour qu'il implémente IExpirable. Dans cette classe, tu lances un timer qui va purger la collection à la fréquence que tu veux :

    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
    public class AutoPurgeCollection<T> : Collection<T>, IDisposable
        where T : IExpirable
    {
        private readonly TimeSpan _itemLifeTime;
        private readonly System.Timers.Timer _purgeTimer;
     
        public AutoPurgeCollection(TimeSpan itemLifeTime, TimeSpan purgeInterval)
        {
            _itemLifeTime = itemLifeTime;
            _purgeTimer = new System.Timers.Timer(purgeInterval.TotalMilliseconds);
            _purgeTimer.Elapsed += (sender, e) => Purge();
            _purgeTimer.AutoReset = true;
            _purgeTimer.Start();
        }
     
        protected virtual void Purge()
        {
            DateTime now = DateTime.Now;
            var itemsToRemove = Items.Where(i => now - i.CreationDate > _itemLifeTime).ToArray();
            foreach (var item in itemsToRemove)
            {
                Items.Remove(item);
            }
        }
     
        public void Dispose()
        {
            _purgeTimer.Dispose();
        }
    }
    Je pense qu'il vaut mieux purger la collection à intervalle régulier, plutot qu'à chaque accès à un de ces membres, parce que sinon ça va tuer les perfs (la recherche des éléments à supprimer étant en temps linéaire)

    L'inconvénient c'est qu'il faudrait rajouter un mécanisme de synchro (lock par exemple) pour éviter que la collection ne soit purgée pendant qu'on l'énumère...

  6. #6
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Par défaut
    Ca me parait dangereux de mettre la responsabilité aux enfants et ca risque de faire beaucoup de timers!

  7. #7
    Membre éprouvé Avatar de swif79
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2009
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2009
    Messages : 79
    Par défaut
    J'avais cru comprendre que la DateTime contenue dans Key était la date d'expiration de son élément, du coup j'ai gratté ce qui suit, vous en pensez quoi ? j'ai pas trop tester et je me demande si ça n'est pas risqué.

    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
    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
     
    public class TimerList : IEnumerable<Key>
        {
            internal readonly List<Key> list = new List<Key>();
            internal List<DateTime> dateList = new List<DateTime>();
            internal System.Windows.Forms.Timer tmr = new System.Windows.Forms.Timer();
            bool CanAttach = true;
     
            public TimerList()
            {
                this.tmr.Tick += new EventHandler(tmr_Tick);
            }
     
            private void tmr_Tick(object sender, EventArgs e)
            {
                this.tmr.Enabled = false;
                DateTime date = (DateTime)this.tmr.Tag;
     
                lock (this.list)
                {
                    varToRemove = 
                                    from key in this.list
                                    where key.EndDate == date
                                    select key;
     
                    CanAttach = false;
     
                    foreach(Key k in ToRemove)
                          this.Remove(k);
     
                    CanAttach = true;
                    this.AttachTimer();
                }          
            }
     
            private int _Count = 0;
            public int Count
            {
                get { return _Count; }
            }
     
            public Key this[int n]
            {
                get
                {
                    if (n < this._Count)
                        return this.list[n];
                    else
                        throw new ArgumentOutOfRangeException();
                }
            }
     
            public bool Add(Key item)
            {
                if (this.list.Contains(item))
                    return false;
     
                this.list.Add(item);
                this.dateList.Add(item.EndDate);
                this.AttachTimer();
     
                _Count++;
     
                return true;
            }
     
            private void AttachTimer()
            {   
                this.dateList.Sort();
                if (this.dateList.Count > 0)
                {
                    DateTime Now = DateTime.Now;
                    this.tmr.Tag = this.dateList[0];
     
                    if(Now < this.dateList[0])
                          this.tmr.Interval = (int)(this.dateList[0] - DateTime.Now).TotalMilliseconds;
                    else
                          this.tmr.Interval = 10;
                    this.tmr.Enabled = true;
                }
            }
     
            public bool Remove(Key item)
            {
                if (!this.list.Contains(item))
                    return false;
     
                this.list.Remove(item);
     
                this.dateList.Remove(item.EndDate);
                if(CanAttach)
                      this.AttachTimer();
     
                _Count--;
                return true;
            }
     
            public bool Contains(Key item)
            {
                return this.list.Contains(item);
            }
     
            public Key[] ToArray()
            {
                return this.list.ToArray();
            }
     
            public IEnumerator<Key> GetEnumerator()
            {
                return this.list.GetEnumerator();
            }
     
            IEnumerator IEnumerable.GetEnumerator()
            {
                return this.list.GetEnumerator();
            }
        }

  8. #8
    Membre expérimenté
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Par défaut
    Et pourquoi dans ces propositions personne ne semble retenir l'idée de la listre triée ?

    Quand on cree une liste sur une Lisr on ne fait que creer une liste de reference sur la liste originale.

    On peut donc appliquer facilement plusieurs tris sur une meme liste d'objet
    Dans le cas present le tri permet d'éviter d'avoir a parcourir toute la liste a chaque evenement clean
    Il faut juste bien gere l'insertion d'un nouvel objet mais ce sera moins lourd que le parcours systématique !

  9. #9
    Membre confirmé Avatar de istace.emmanuel
    Homme Profil pro
    Senior Full-Stack .Net Developer
    Inscrit en
    Août 2009
    Messages
    125
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Belgique

    Informations professionnelles :
    Activité : Senior Full-Stack .Net Developer
    Secteur : Conseil

    Informations forums :
    Inscription : Août 2009
    Messages : 125
    Par défaut
    merci beaucoup

    Bon je vais compiler tout ça et voir avec un teste de charge quelle solution est la plus performante, TimerList de swiff, Liste trié de olibara et la AutoPurgeCollection de tomlev.

    Je vous tiens au courant.

    (Par contre j'utilisais un System.Threading.Timer et pas un System.Windows.Forms.Timer, il y a t il des différences fonctionnelles ? J'ai l'impression que c'est grosso modo kiff kiff d'après la msdn)

    Voila ce que ça donnait avec les timers/Events (C'est crade mais c'était pour tester)

    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
     
        [DataContract]
        public class Key
        {
            #region Constructor
            public Key()
            {
                this.value = System.Guid.NewGuid().ToString();
                this.date = DateTime.Now;
                this.Clock = new Timer(new TimerCallback(AskDeletation), null, 5000, Timeout.Infinite);
            }
            #endregion
     
            [DataMember]
            public string value { get; set; }
     
            [DataMember]
            public DateTime date { get; set; }
     
            #region Deletation Handler
            Timer Clock;
     
            public event EventHandler<KeyTimeOutEvent> RaiseDeletationDemand;
     
            private void AskDeletation(object sender)
            {
                OnRaiseDeletationDemand(new KeyTimeOutEvent("Delete"));
            }
     
            protected virtual void OnRaiseDeletationDemand(KeyTimeOutEvent e)
            {
                EventHandler<KeyTimeOutEvent> handler = RaiseDeletationDemand;
     
                if (handler != null)
                {
                    e.Message += String.Format(" at {0}", DateTime.Now.ToString());
                    handler(this, e);
                }
            }
            #endregion
        }
     
        [DataContract]
        public class KeyTimeOutEvent : EventArgs
        {
            #region Constructor
            public KeyTimeOutEvent(string s)
            {
                this.Message = s;
            }
            #endregion
     
            [DataMember]
            public string Message { get; set; }
        }
    Coté hôte :

    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
     
                #region Key Methods
                List<Key> GUID = new List<Key>();
     
                private void AddKeyToList(Key k)
                {
                    GUID.Add(k);
                    k.RaiseDeletationDemand += new EventHandler<KeyTimeOutEvent>(AskDeletationHandler);
                }
     
                private void AskDeletationHandler(object sender, KeyTimeOutEvent e)
                {
                    this.GUID.Remove((Key)sender);
                }
                #endregion

Discussions similaires

  1. Pas d'affiche d'items dans une list box
    Par breezer911 dans le forum Windows Forms
    Réponses: 1
    Dernier message: 08/03/2007, 17h06
  2. Cocher un items dans une liste de type TCheckListBox
    Par Faith's Fall dans le forum C++Builder
    Réponses: 2
    Dernier message: 02/03/2007, 20h48
  3. [VB6] Double click d'un item dans une list...
    Par Jihnn dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 15/04/2006, 18h56
  4. Selectionner automatiquement un item dans une liste
    Par nebule dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 09/12/2004, 17h03
  5. Réponses: 2
    Dernier message: 17/08/2003, 20h07

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