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

Framework .NET Discussion :

principe d'invariance -boxing dans une collection


Sujet :

Framework .NET

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    968
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 968
    Points : 141
    Points
    141
    Par défaut principe d'invariance -boxing dans une collection
    Bonjour,

    Je vous remercie beaucoup de bien vouloir m'aider à répondre aux questions suivantes

    Principe d'invariance:

    Ce principe s'applique-t-il uniquement s'il existe un lien d'héritage entre deux types A et B?
    Ex:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Wrapper<string>stringWrapper;
     IWrapper<Object> storedObjectWrapper= stringWrapper;

    Dans ce cas, l'interface IWrapper<T> est invariante et l'instruction IWrapper<Object> storedObjectWrapper= stringWrapper;
    renverra une erreur à l'execution.

    Or est-ce du fait que le type string est un sous type de Object ou, si j'avais ecrit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    IWrapper<int> storedObjectWrapper= stringWrapper;
    cette instruction n'aurait pas pu s'exécuter de toute manière.

    Je vous remercie de votre aide sur ce point.

    Pouvez-vous m'expliquer pourquoi la restriction liée à l'invariance s'applique aux types génériques et non pas aux types non génériques?

    Ensuite, du fait qu'un type est générique, il contient , pour toutes les instances de ce type, les mêmes méthodes(que ce soit dans le cas où le type générique est remplace par le type Object ou qu'il soit remplacé par le type int) .
    Pourquoi donc empêcher une telle instruction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    IWrapper<Object> storedObjectWrapper= stringWrapper;

    Autre point: si on stocke des valeurs de type simple(int, etc...) dans une collection, le compilateur génère du code pour boxer les données .
    Pouvez-vous me confirmer que cela ne concerne que les éléments de type valeur et non les éléments de type référence(une telle opération ne s'affectuera pas si je stocke directement des valeurs de type classe ou interface ou de tout type référence).
    Je vous en remercie .

    Portée d'une lambda expression: j'apprends que si j'affecte une méthode anonyme (par le biais d'une lambda expression)à un delegue nomme del,et que dans le code de cete lambda exprsion je modifie une variable qui a été définie en dehors de la lambda expression, cette variable reste en mémoire jusqu'à ce que toutes les références au délégué del aient disparu.
    Cela signifie t-il que cette variable reste en mémoire jusqu'à ce que ce délégué ne pointe plus vers aucune méthode, c'est à dire soit =null



    opérateurs unaires + et -: s'agit il des opérateurs qui indiquent qu'un nombre est négatif ou positif?

    Par ailleurs, je ne savais pas que les opérateurs true et false sont des opérateurs unaires.
    Pouvez vous me donner un exemple de leur utilisation.

    Je vous en remercie .

    opérateurs de conversion: sont ils simplement tous ceux qui permettent de caster dans un type définiint), (string) etc...?
    Que signifie qu'un opérateur est non polymorphe.


    Je vous remercie beaucoup de votre aide sur tous ces points .

    Bien cordialement.

    curieuse_prog

  2. #2
    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
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par new_wave Voir le message
    Principe d'invariance:

    Ce principe s'applique-t-il uniquement s'il existe un lien d'héritage entre deux types A et B?
    Ex:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Wrapper<string>stringWrapper;
     IWrapper<Object> storedObjectWrapper= stringWrapper;

    Dans ce cas, l'interface IWrapper<T> est invariante et l'instruction IWrapper<Object> storedObjectWrapper= stringWrapper;
    renverra une erreur à l'execution.

    Or est-ce du fait que le type string est un sous type de Object ou, si j'avais ecrit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    IWrapper<int> storedObjectWrapper= stringWrapper;
    cette instruction n'aurait pas pu s'exécuter de toute manière.
    Pour qu'un IWrapper<B> puisse être affecté à un IWrapper<A>, il faut
    - que l'interface IWrapper<T> soit covariante
    - qu'il existe une conversion de référence de B vers A (autrement dit, que B hérite de A)

    ou alors :

    - que l'interface IWrapper<T> soit contravariante
    - qu'il existe une conversion de référence de A vers B (autrement dit, que A hérite de B)


    Si IWrapper<T> est invariante (ni covariante, ni contravariante), tu ne pourras jamais affecter un IWrapper<B> à un IWrapper<A> (à moins que A et B soient le même type...)

    D'autre part, cela ne fonctionne qu'avec les types référence ; si A ou B est un type valeur, il n'y a pas de "conversion de référence" possible entre les 2, et donc pas de variance. Donc dans ton 2e exemple, même si l'interface n'était pas invariante, ce ne serait pas possible.

    Citation Envoyé par new_wave Voir le message
    Pouvez-vous m'expliquer pourquoi la restriction liée à l'invariance s'applique aux types génériques et non pas aux types non génériques?
    Si tu poses cette question, c'est que tu n'as vraiment pas compris ce qu'est la variance... La variance (en C# du moins) n'a de sens que pour des types génériques, de par sa définition. Regarde cet article pour plus d'infos sur le sujet : Variance en C# 4.0

    Citation Envoyé par new_wave Voir le message
    Ensuite, du fait qu'un type est générique, il contient , pour toutes les instances de ce type, les mêmes méthodes(que ce soit dans le cas où le type générique est remplace par le type Object ou qu'il soit remplacé par le type int) .
    Je ne comprends pas ta phrase. Ca n'a rien à voir avec le fait que le type soit générique, c'est vrai pour n'importe quel type.

    Citation Envoyé par new_wave Voir le message
    Pourquoi donc empêcher une telle instruction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    IWrapper<Object> storedObjectWrapper= stringWrapper;
    A cause de cette histoire de variance. Il ne suffit pas que String hérite de Object, il faut aussi que IWrapper<T> soit covariante.

    Prenons un exemple plus concret, avec l'interface IList<T>. Le morceau de code suivant n'est pas légal, mais supposons qu'il le soit et observons les conséquences :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    IList<string> stringList = new List<string>();
    IList<object> objectList = stringList;
     
    objectList.Add("hello world"); // OK, on peut ajouter une chaine à une List<string>
    objectList.Add(new Toto()); // Oups !
    Du point de vue du compilateur, la dernière ligne est parfaitement légale, puisque Toto (comme tous les autres types) hérite de object, donc on peut ajouter un Toto à une IList<object>, non ? Sauf qu'en réalité, la liste est toujours une instance de List<string>, qui ne peut contenir que des strings ! Donc si ce morceau de code était légal, il causerait une erreur à l'exécution...

    C'est pour ça que IList<T> n'est pas covariante : si elle l'était, cela permettrait des erreurs de typage que le compilateur ne pourrait pas détecter.

    Pour ton IWrapper<T>, tout dépend de ce qu'il fait : si le type T apparait seulement "en sortie" (par exemple comme valeur de retour d'une propriété ou d'une méthode), alors on peut déclarer IWrapper<T> comme étant covariante en T : interface IWrapper<out T>. Mais si ce n'est pas le cas, rien ne dit que la conversion de IWrapper<string> en IWrapper<object> soit sûre, donc elle est considérée comme illégale.

    Citation Envoyé par new_wave Voir le message
    Pourquoi donc empêcher une telle instruction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    IWrapper<Object> storedObjectWrapper= stringWrapper;
    Pas nécessairement. Si c'est une List<int> par exemple, il n'y a pas de boxing. Mais si c'est une collection non typée comme ArrayList, ou une collection générique comme List<object>, les valeurs seront effectivement boxées.

    Citation Envoyé par new_wave Voir le message
    opérateurs de conversion: sont ils simplement tous ceux qui permettent de caster dans un type définiint), (string) etc...?
    Oui, le boxing concerne uniquement les types valeurs. Il se produit quand tu passes une instance d'un type valeur à un endroit où un type référence est attendu (par exemple object, ou une interface)

    Citation Envoyé par new_wave Voir le message
    Que signifie qu'un opérateur est non polymorphe.
    Le délégué pointe toujours vers une méthode ; il est "immuable" (immutable en anglais), donc une fois créé, il ne change plus. Donc pour reprendre ta phrase de façon plus exacte :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    IList<string> stringList = new List<string>();
    IList<object> objectList = stringList;
     
    objectList.Add("hello world"); // OK, on peut ajouter une chaine à une List<string>
    objectList.Add(new Toto()); // Oups !
    (à strictement parler, elle restera en mémoire jusqu'à ce que le GC soit passer par là bien sûr...)

    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
    void Main()
    {
        var f1 = new Foo(null);
        var f2 = new Foo(string.Empty);
        var f3 = new Foo("hello world");
     
        if (f1)
            Console.WriteLine ("f1: true");
        else
            Console.WriteLine ("f1: false");
     
        if (f2)
            Console.WriteLine ("f2: true");
        else
            Console.WriteLine ("f2: false");
     
        if (f3)
            Console.WriteLine ("f3: true");
        else
            Console.WriteLine ("f3: false");
    }
     
     
    class Foo
    {
        private readonly string _value;
        public Foo(string value)
        {
            _value = value;
        }
     
        public string Value
        {
            get { return _value; }
        }
     
        public static bool operator true(Foo foo)
        {
            return !string.IsNullOrEmpty(foo.Value);
        }
     
        public static bool operator false(Foo foo)
        {
            return string.IsNullOrEmpty(foo.Value);
        }
    }
    Oui. Sauf que l'opérateur unaire "+" ne sert à rien, il est implicite. Que tu écrives 42 ou +42, ça revient au même.


    Ca indique si un objet doit être considéré comme true ou false dans une condition. Par exemple, on peut créer une classe Foo qui est considérée comme true si ça valeur n'est pas nulle ou vide :

    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
    void Main()
    {
        var f1 = new Foo(null);
        var f2 = new Foo(string.Empty);
        var f3 = new Foo("hello world");
     
        if (f1)
            Console.WriteLine ("f1: true");
        else
            Console.WriteLine ("f1: false");
     
        if (f2)
            Console.WriteLine ("f2: true");
        else
            Console.WriteLine ("f2: false");
     
        if (f3)
            Console.WriteLine ("f3: true");
        else
            Console.WriteLine ("f3: false");
    }
     
     
    class Foo
    {
        private readonly string _value;
        public Foo(string value)
        {
            _value = value;
        }
     
        public string Value
        {
            get { return _value; }
        }
     
        public static bool operator true(Foo foo)
        {
            return !string.IsNullOrEmpty(foo.Value);
        }
     
        public static bool operator false(Foo foo)
        {
            return string.IsNullOrEmpty(foo.Value);
        }
    }
    En pratique ça ne sert pas beaucoup...

    Citation Envoyé par new_wave Voir le message
    opérateurs de conversion: sont ils simplement tous ceux qui permettent de caster dans un type définiint), (string) etc...?
    Ce sont tout simplement les opérateurs qui permettent de convertir un type vers un autre. Cas particulier : certaines conversions entre les types primitifs (int, double, etc) sont définis au niveau du langage lui-même, et non par un opérateur dans le code.

    Citation Envoyé par new_wave Voir le message
    Que signifie qu'un opérateur est non polymorphe.
    Que le polymorphisme ne s'applique pas. Ce qui est logique d'ailleurs, puisque les opérateurs sont définis comme des méthodes statiques, et que le polymorphisme n'a de sens que pour des méthodes d'instance...

Discussions similaires

  1. [VB.NET] Suppression d'objets dans une collection
    Par master56 dans le forum VB.NET
    Réponses: 7
    Dernier message: 03/06/2010, 21h46
  2. [9i] insertion dans une collection
    Par meuledor dans le forum Oracle
    Réponses: 2
    Dernier message: 17/02/2006, 12h02
  3. Réponses: 8
    Dernier message: 03/02/2006, 15h15
  4. [PL/SQL] Charger une table dans une collection
    Par nosnoss dans le forum Oracle
    Réponses: 10
    Dernier message: 03/03/2005, 17h56
  5. Controle dans une collection
    Par rolototo dans le forum VB 6 et antérieur
    Réponses: 6
    Dernier message: 07/02/2005, 14h12

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