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 :

Collection basée sur une autre.


Sujet :

C#

  1. #1
    maa
    maa est déconnecté
    Membre éclairé
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Par défaut Collection basée sur une autre.
    Bonjour,

    Voici un problème sur lequel je retombe souvent.

    Etant donné une collection, comment créer une seconde collection dont chaque élément renvoi une expression basée sur un élément correspondant de la première collection.

    La première solution qui vient à l'idée serait d'utiliser une énumération :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    MaPremiereCollection.Select(y=>expression(y));
    Le problème est que l'expression est réévaluée à chaque appel sur l'énumération. Si l'expression est lourde ça peut être gourmand en terme de performance. Pire, cette solution n'est pas utilisable si on renvoi dans Select() une nouvelle instance. Par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    MaPremiereCollection.Select(y=>new NewObject(expression(y)));
    car alors à chaque appel sur un élément de l'énumération on crée une nouvelle instance d'objet.

    On pourrait alors penser faire un ToList() pour fixer cette énumération dans une collection, mais alors celle-ci sera en décalage avec la collection de base si cette dernière à été mise à jour.

    Ce que je pensais ensuite faire, c'est synchroniser la première collection et la seconde avec des événements, mais cela est fastidieux à mettre en place à chaque fois...

    Auriez-vous une solution/un pattern pour ce problème ?

    merci d'avance.

    mathmax

  2. #2
    Membre Expert Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Par défaut
    Salut,

    en gros, à partir de ta liste de xi, tu veux avoir un accès facile à une liste de f(xi).
    Plutôt que faire une seconde liste contenant tous les éléments de la première transformés, pourquoi ne pas faire une liste qui n'applique ta fonction f que quand c'est nécessaire ? C'est à ta dire, tant qu'on a pas fait NewList[i], tu n'appliques pas f au i-ième élément de la liste d'origine.
    Après, tu peux rajouter du cache dans cette liste si besoin.

    Tu as vu la BindingListView ? C'est ce qui est fait dedans, il me semble. Et puis, les sources du Framework étant (ou bientôt) dispo, tu pourras voir comment la DataView fonctionne

  3. #3
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 602
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 65
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 602
    Par défaut
    Citation Envoyé par Guulh Voir le message
    Et puis, les sources du Framework étant (ou bientôt) dispo, tu pourras voir comment la DataView fonctionne
    Bof .... avec Reflector ça se fait très bien

  4. #4
    Rédacteur
    Avatar de SaumonAgile
    Homme Profil pro
    Team leader
    Inscrit en
    Avril 2007
    Messages
    4 028
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Team leader
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2007
    Messages : 4 028
    Par défaut
    Citation Envoyé par Bluedeep Voir le message
    Bof .... avec Reflector ça se fait très bien
    Oui mais attention à la propriété intellectuelle. D'ailleurs open source ou pas, la propriété intellectuelle s'appliquera toujours. Prudence.
    Besoin d'un MessageBox amélioré ? InformationBox pour .NET 1.1, 2.0, 3.0, 3.5, 4.0 sous license Apache 2.0.

    Bonnes pratiques pour les accès aux données
    Débogage efficace en .NET
    LINQ to Objects : l'envers du décor

    Mon profil LinkedIn - MCT - MCPD WinForms - MCTS Applications Distribuées - MCTS WCF - MCTS WCF 4.0 - MCTS SQL Server 2008, Database Development - Mon blog - Twitter

  5. #5
    maa
    maa est déconnecté
    Membre éclairé
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Par défaut
    en gros, à partir de ta liste de xi, tu veux avoir un accès facile à une liste de f(xi).
    Plutôt que faire une seconde liste contenant tous les éléments de la première transformés, pourquoi ne pas faire une liste qui n'applique ta fonction f que quand c'est nécessaire ? C'est à ta dire, tant qu'on a pas fait NewList[i], tu n'appliques pas f au i-ième élément de la liste d'origine.
    C'est exactement ce que je voudrais. SI tu dis que la BindingListView fait cela, c'est cool. Je n'ai malheureusement pas trouvé comment faire avec l'implémentation que j'ai. J'utilise cette BindingListView . Peut-être en utilises-tu une autre ? Ou peut-être que c'est possible à faire avec celle que j'ai ? Quelles méthodes/propriétés utilises-tu dans ce cas ?

  6. #6
    Membre Expert Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Par défaut
    Citation Envoyé par maa Voir le message
    C'est exactement ce que je voudrais. SI tu dis que la BindingListView fait cela, c'est cool. Je n'ai malheureusement pas trouvé comment faire avec l'implémentation que j'ai. J'utilise cette BindingListView . Peut-être en utilises-tu une autre ? Ou peut-être que c'est possible à faire avec celle que j'ai ? Quelles méthodes/propriétés utilises-tu dans ce cas ?
    J'utilise celle-là, c'est moi qui t'avais filé le lien il y a quelques semaines La BLW encapsule chaque objet de sa source dans un ObjectView<T>, qui n'est créé que si nécessaire. Tu peux t'en inspirer.

    @SaumonAgile : le but est pas de piquer le code de Crosoft, hein Juste que cette bande de zigotos a pas cru bon d'implémenter un équivalent de la DataView pour les collections classiques, c'est pourquoi ce cher maa essaie depuis un certain temps maintenant de le faire.

  7. #7
    maa
    maa est déconnecté
    Membre éclairé
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Par défaut
    J'utilise celle-là, c'est moi qui t'avais filé le lien il y a quelques semaines
    Oui en effet. Merci beaucoup d'ailleurs.
    La BLW encapsule chaque objet de sa source dans un ObjectView<T>, qui n'est créé que si nécessaire. Tu peux t'en inspirer.
    Là je vois pas trop comment cela pourrait m'aider. J'ai un moyen de contrôler comment cet ObjectView est crée (je veux dire sans modifier le code) ? Et comment puis-je créer un nouvel objet se basant sur un objet de la collection d'origine.
    Par exemple, j'ai une collection de Product. Je veux que ma BindingListView reflète une collection de ProductWraper, un ProductWraper s'obtenant en faisant new ProductWraper(productAssocié). Comment faire cela ?
    Si tu m'aide à résoudre ce problème alors je fais un grand pas en avant. Comme tu l'as dit, cela fait un moment que je rencontre des problèmes autour de ce sujet...

  8. #8
    Membre Expert Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Par défaut
    J'ai des problèmes très similaires au tien. Pour l'instant, je fais :
    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
    BindingList<Product> source;
    BindingList<ProductWrapper> wrappedSource; // avec abonnement à l'event ListChanged de la précédente :
    private void OnSourceChanged(object sender, ListChangedEventArgs e)
    {
        switch (e.ListChangedType)
            {
            case ListChangedType.ItemAdded: wrappedSource.Add(new ProductWrapper((sender as ILIst<Product>)[e.NewIndex])); break;
            case ListChangedType.ItemDeleted: // faire un traitement approprié
            case ListChangedType.Reset:
                _wrappedSource.Clear();
                foreach (Product product in (sender as IList<Product>))
                    _wrappedSource.Add(new ProductWrapper(product));
                break;
            default: break;
    	}
    }
     
    BindingListView<ProductWrapper>; // avec pour DataSource la précédente.
    C'est moche, mais vu que ça marche et que j'ai pas insisté... (pire : mes Product encapsulent eux-même une autre classe en provenance d'un serveur...)

    Ce qu'on peut envisager, c'est d'avoir une BindingListView <T,U>, avec T le type source et U le type wrappé, en spécifiant un moyen de passer de l'un à l'autre. Que ce soit un constructeur U(T t), un opérateur de conversion, etc. Au boulot !

    Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    abstract class Wrapper<T>
    {
    public Wrapper(T source);
    }
    Et là, ProductWrapper hérite de Wrapper, et tu peux faire un BLW<T, U> perso avec comme contrainte U : Wrapper<T>.

    Dommage que les interfaces ne puissent pas spécifier de constructeur, d'ailleurs. Doit y avoir une bonne raison qui m'échappe.

    Je pars du principe que le type de base doit être indépendant, mais que par contre qu'on a entièrement la main sur le type wrapper et qu'on peut donc le faire hériter de ce qu'on veut.

    [edit] Après réflexion, vu que les constructeurs ne s'héritent pas, le code ci-dessus est faux. Mais bon y'a de l'idée

  9. #9
    maa
    maa est déconnecté
    Membre éclairé
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Par défaut
    Ok, c'est en gros ce que j'ai fait aussi en attendant :

    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
     
        public class SynchronizedView<TBase, TView> : IEnumerable<TView> where TView : class
        {
            private BindingList<TBase> _CollectionBase;
            private List<TView> _CollectionView;
            private Func<TBase, TView> _Selector;
            private Action<TBase, TView> _Modificator;
     
            public SynchronizedView(BindingList<TBase> collectionBase, Func<TBase, TView> selector, Action<TBase, TView> modificator)
                : this(collectionBase, selector)
            {
                _Modificator = modificator;
            }
     
            public SynchronizedView(BindingList<TBase> collectionBase, Func<TBase, TView> selector)
            {
                _CollectionBase = collectionBase;
                _Selector = selector;
                _CollectionView = _CollectionBase.Select(selector).ToList();
                _CollectionBase.ListChanged += new ListChangedEventHandler(_CollectionBase_ListChanged);
            }
     
            void _CollectionBase_ListChanged(object sender, ListChangedEventArgs e)
            {
                switch (e.ListChangedType)
                {
                    case (ListChangedType.ItemAdded):
                        _CollectionView.Insert(e.NewIndex, _Selector(_CollectionBase[e.NewIndex]));
                        break;
                    case (ListChangedType.ItemDeleted):
                        _CollectionView.RemoveAt(e.NewIndex);
                        break;
                    case(ListChangedType.Reset):
                        _CollectionView.Clear();
                    case (ListChangedType.ItemChanged):
                        if (_Modificator != null)
                            _Modificator(_CollectionBase[e.NewIndex], _CollectionView[e.NewIndex]);
                        break;
                }
            }
     
     
            #region IEnumerable<TView> Members
     
            public IEnumerator<TView> GetEnumerator()
            {
                return _CollectionView.GetEnumerator();
            }
     
            #endregion
     
            #region IEnumerable Members
     
            IEnumerator IEnumerable.GetEnumerator()
            {
                return _CollectionView.GetEnumerator();
            }
     
            #endregion
        }

    mais tu m'avais parlé d'une solution avec la BindingListView... ? Ne permet t-elle que de filtrer, trier, concaténer des collections existantes ? Ou peut-on préciser un transformateur ou une expression de sorte que les objectView renvoient autre chose (une expression basée sur un objet de la collection initiale ou même un nouvel objet, par exemple un wrapper) ?

  10. #10
    Membre Expert Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Par défaut
    Pour parler en termes BDD, La BLW permet d'agréger n listes et de filtrer sur les lignes, mais n'agit pas sur les colonnes. Pas d'ajout, pas de modification, pas de suppression, rien. Comme la DataView, en fait.

  11. #11
    maa
    maa est déconnecté
    Membre éclairé
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Par défaut
    Alors je ne suis pas sûr d'avoir compris ce que tu avais dit là :

    en gros, à partir de ta liste de xi, tu veux avoir un accès facile à une liste de f(xi).
    Plutôt que faire une seconde liste contenant tous les éléments de la première transformés, pourquoi ne pas faire une liste qui n'applique ta fonction f que quand c'est nécessaire ? C'est à ta dire, tant qu'on a pas fait NewList[i], tu n'appliques pas f au i-ième élément de la liste d'origine.
    Après, tu peux rajouter du cache dans cette liste si besoin.

    Tu as vu la BindingListView ? C'est ce qui est fait dedans, il me semble.
    Je croyais que tu disais qu'on pouvait faire cela avec la BindingListView.

    Sinon, il ne reste qu'à améliorer la BindingListView...

  12. #12
    Membre Expert Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Par défaut
    La BLW est très générale, donc ObjectView<T> n'apporte rien en plus de T. Je voulais dire que la BLW, avec comme DataSource un IList<T>, était elle même une IList<ObjectView<T>>, et que tu pourrais la modifier pour que cet ObjectView<T> fasse ce que tu veux. Comme j'écrivais plus haut, il doit y avoir moyen de faire une BLW<TSource, TWrapped> pourvu qu'on ait un moyen de convertir l'un en l'autre.

  13. #13
    maa
    maa est déconnecté
    Membre éclairé
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Par défaut
    Oui c'est un peu ce que j'avais fait avec ma SynchronizedView<TBase, TView> rapidement bricolé pour les besoins du moments.
    Mais c'est vrai qu'avoir une BLW bien faite et gérant un plus grand nombre de cas serait super... Qui a envie de développer ?

Discussions similaires

  1. requete suppression avec critere base sur une autre requete
    Par strouve dans le forum Requêtes et SQL.
    Réponses: 3
    Dernier message: 16/07/2012, 10h18
  2. Réponses: 14
    Dernier message: 31/08/2010, 11h25
  3. Réponses: 7
    Dernier message: 21/04/2010, 19h27
  4. Réponses: 2
    Dernier message: 23/10/2007, 08h11
  5. Formulaire avec liste basée sur une autre table
    Par sabotage dans le forum Langage SQL
    Réponses: 6
    Dernier message: 10/08/2005, 13h43

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