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 :

Problème de conversion d'une liste d'interface à son classe originale


Sujet :

C#

  1. #1
    Futur Membre du Club
    Inscrit en
    Février 2010
    Messages
    7
    Détails du profil
    Informations forums :
    Inscription : Février 2010
    Messages : 7
    Points : 7
    Points
    7
    Par défaut Problème de conversion d'une liste d'interface à son classe originale
    Bonjour
    Je me suis bloqué au niveaux d'une conversion d'une liste d'interface à son propre classe.

    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
     
    /*Interface IField*/
    public interface IField
        {
            string FieldName { get; set; }
            string FieldType { get; set; } 
     
        }
     
    /*Son implémentation*/
    public class Field : IField
        {
                 public Field(string fieldName, string fieldType)
                 {
                    this.FieldName = fieldName;
                    this._fieldType = fieldType;
                 }
     
                 public string FieldName {   get ;   set;  }
                 public string FieldType{   get ;   set;  }
      }
    La 2ème interface qui parmi de ces attributs un de type IField.

    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
     
    public interface IProtocol
        {
            string NameProtocol { get; set; }
            string Id { get; set; }
            List<IField> FieldList { get; set; }
        }
    /*Son implémentation*/
     
    public class Protocol : IProtocol
        {
     
          public Protocol(string nameProtocol, string id, List<IField> fieldList)
            {
                this.NameProtocol = nameProtocol;
                this.Id = id;
                this.FieldList = fieldList;
            }
     
             public string NameProtocol{   get ;   set;  }
             public string Id{   get ;   set;  }
             public List<IField> FieldList{   get ;   set;  }
      }
    Ce que je veux c'est convertir la liste de IField en liste de Field pour avoir un constructeur où FieldList est de type List<Field> comme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
     public Protocol(string nameProtocol, string id, List<Field> fieldList)
            {
                this.NameProtocol = nameProtocol;
                this.Id = id;
                this.FieldList = fieldList;
            }
    
     public List<Field> FieldList{   get ;   set;  }
    Le problème si j'utilise le 2eme constructeur j'aurais un problème d'implémentation car son Interface possède une liste de IField.
    Celle la sa marche: IField Ifield = new Field();
    Mais celle ci non: List<IField> fields = new List<Field>(); "Err convertion"
    Avez vous de solution?

    Merci
    Cordialement

  2. #2
    Membre émérite Avatar de meziantou
    Homme Profil pro
    Ingénieur R&D
    Inscrit en
    Avril 2010
    Messages
    1 223
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Canada

    Informations professionnelles :
    Activité : Ingénieur R&D
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2010
    Messages : 1 223
    Points : 2 439
    Points
    2 439
    Par défaut
    Ca s'appelle la covariance.
    En c# 4 il y a 2 mot clés pour les génériques in et out.

  3. #3
    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
    Il n'y a aucune relation d'héritage entre List<Field> et List<IField>, l'affectation que tu cherches à faire n'est donc pas possible. Si c'était possible, ça permettrait de faire des choses comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class Field : IField { ... }
    class Field2 : IField { ... }
     
    List<Field> fields = new List<Field>();
    List<IField> ifields = fields; // interdit, mais supposons que ce soit possible
    ifields.Add(new Field2()); // oops, on ajoute un Field2 à une liste de Field... BOOM !
    Une solution est d'utiliser ToList (mais ça crée une nouvelle liste) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    this.FieldList = fieldList.ToList<IField>();
    Citation Envoyé par meziantou Voir le message
    Ca s'appelle la covariance.
    Sauf qu'ici la covariance ne s'applique pas, car seules les interfaces et délégués peuvent être covariants (ou contravariants), et List<T> est une classe. Et de toutes façons, même l'interface IList<T> n'est pas covariante (ni contravariante) en T, car T apparait aussi bien en sortie qu'en entrée.

  4. #4
    Futur Membre du Club
    Inscrit en
    Février 2010
    Messages
    7
    Détails du profil
    Informations forums :
    Inscription : Février 2010
    Messages : 7
    Points : 7
    Points
    7
    Par défaut
    Citation Envoyé par tomlev Voir le message
    Il n'y a aucune relation d'héritage entre List<Field> et List<IField>, l'affectation que tu cherches à faire n'est donc pas possible. Si c'était possible, ça permettrait de faire des choses comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class Field : IField { ... }
    class Field2 : IField { ... }
     
    List<Field> fields = new List<Field>();
    List<IField> ifields = fields; // interdit, mais supposons que ce soit possible
    ifields.Add(new Field2()); // oops, on ajoute un Field2 à une liste de Field... BOOM !
    Une solution est d'utiliser ToList (mais ça crée une nouvelle liste) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    this.FieldList = fieldList.ToList<IField>();


    Sauf qu'ici la covariance ne s'applique pas, car seules les interfaces et délégués peuvent être covariants (ou contravariants), et List<T> est une classe. Et de toutes façons, même l'interface IList<T> n'est pas covariante (ni contravariante) en T, car T apparait aussi bien en sortie qu'en entrée.
    Merci pour votre réponse mais this.FieldList = fieldList.ToList<IField>(); vas convertir list<IField> en list<Field> mais j'aurais une erreur de convertion d'une list vers classe, sachant que Field implémente IField aussi j'ai pas compris la covariance, pouvez vous me donner un exemple bien préçi svp !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     public Protocol(string nameProtocol, string id, List<Field> fieldList, )
            {
            //lp = _fieldList.ConvertAll(new Converter<IField, Field>(IFieldToField));
                            
                this.NameProtocol = nameProtocol;
                this.LongName = longName;
                this.Id = id;
                this.FieldList = fieldList.ToList<Field>(); //Err convertion
                this.Encapsulation = encapsulation;
    
               
    
            }

  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
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par khalifanizar Voir le message
    Merci pour votre réponse mais this.FieldList = fieldList.ToList<IField>(); vas convertir list<IField> en list<Field>
    Non, ça va convertir List<Field> en List<IField>... dans ton code tu as écrit .ToList<Field>() au lieu de .ToList<IField>()
    Citation Envoyé par khalifanizar Voir le message
    aussi j'ai pas compris la covariance, pouvez vous me donner un exemple bien préçi svp !
    Par exemple, IEnumerable<T> est covariant en T, c'est à dire que si Y hérite de X, alors un IEnumerable<Y> peut être affecté à un IEnumerable<X>.

    Exemple avec X = object et Y = string :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    List<string> listOfStrings = new List<string>(); // List<T> implémente IEnumerable<T>
    IEnumerable<object> objects = listOfStrings;
    (une séquence de strings peut être considérée comme une séquence d'objects)

    La contravariance, c'est le contraire. Par exemple, Action<T> est contravariant en T, c'est à dire que si Y hérite de X, alors un Action<X> peut être affecté à un Action<Y> :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Action<object> actionOnObject = o => Console.WriteLine(o.ToString());
    Action<string> actionOnString = actionOnObject;
    actionOnString("Hello");
    (une action qui s'applique à n'importe quel object peut être appliquée à une string, puisqu'une string est un object)

    Pour plus de détails, regarde cet article

  6. #6
    Futur Membre du Club
    Inscrit en
    Février 2010
    Messages
    7
    Détails du profil
    Informations forums :
    Inscription : Février 2010
    Messages : 7
    Points : 7
    Points
    7
    Par défaut
    Citation Envoyé par tomlev Voir le message
    Non, ça va convertir List<Field> en List<IField>... dans ton code tu as écrit .ToList<Field>() au lieu de .ToList<IField>()

    Par exemple, IEnumerable<T> est covariant en T, c'est à dire que si Y hérite de X, alors un IEnumerable<Y> peut être affecté à un IEnumerable<X>.

    Exemple avec X = object et Y = string :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    List<string> listOfStrings = new List<string>(); // List<T> implémente IEnumerable<T>
    IEnumerable<object> objects = listOfStrings;
    (une séquence de strings peut être considérée comme une séquence d'objects)

    La contravariance, c'est le contraire. Par exemple, Action<T> est contravariant en T, c'est à dire que si Y hérite de X, alors un Action<X> peut être affecté à un Action<Y> :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Action<object> actionOnObject = o => Console.WriteLine(o.ToString());
    Action<string> actionOnString = actionOnObject;
    actionOnString("Hello");
    (une action qui s'applique à n'importe quel object peut être appliquée à une string, puisqu'une string est un object)

    Pour plus de détails, regarde cet article
    Merci encore une fois je sais que j'ai mis .ToList<Field>() au lieu de .ToList<IField>() car je veux avoir dans la classe de protocol un attribut List<Field> et non pas List<IField> pour pouvoir sérialiser une liste de protocole y compris une liste de Field de type Field, j'espr que vous m'avez compris bien maintenant!

  7. #7
    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 khalifanizar Voir le message
    je sais que j'ai mis .ToList<Field>() au lieu de .ToList<IField>() car je veux avoir dans la classe de protocol un attribut List<Field> et non pas List<IField> pour pouvoir sérialiser une liste de protocole y compris une liste de Field de type Field
    Bah oui, mais tu as déclaré la propriété comme List<IField>, pas List<Field>... Si tu veux avoir une List<Field>, mais aussi une List<IField> pour respecter le contrat de l'interface, tu peux implémenter explicitement l'interface la propriété FieldList de l'interface :


    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
        public class Protocol : IProtocol
        {
     
          public Protocol(string nameProtocol, string id, List<IField> fieldList)
            {
                this.NameProtocol = nameProtocol;
                this.Id = id;
                this.FieldList = fieldList;
            }
     
             public string NameProtocol{   get ;   set;  }
             public string Id{   get ;   set;  }
             public List<Field> FieldList{   get ;   set;  }
     
             // Implémentation explicite
             List<IField> IProtocol.FieldList
             {
                    get
                    {
                        return this.FieldList.ToList<IField>();
                    }
                    set
                    {
                        this.FieldList = value.Cast<Field>().ToList();
                    }
             }
      }
    Par contre, ça va créer une nouvelle liste à chaque fois que tu appelleras FieldList via l'interface...

  8. #8
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 493
    Points
    5 493
    Par défaut
    IProtocol a t-il vraiment besoin d'exposer une liste ? Une énumération ne pourrait-elle pas suffire ? Puisque IEnumerable<T> est covariante, cela simplifierait les choses.

    Sinon, si le design actuel doit vraiment être conservé, deux solutions :
    * Créer une CovariantList<T> héritant de List<T> mais déclarant T comme covariant (pas sûr que ce soit possible mais à tester)
    * Créer un CovariantListWrapper<TSource, TDest> implémentant IList<TDest> et déclarant un constructeur prenant une IList<TSource> en argument.

  9. #9
    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 DonQuiche Voir le message
    IProtocol a t-il vraiment besoin d'exposer une liste ? Une énumération ne pourrait-elle pas suffire ? Puisque IEnumerable<T> est covariante, cela simplifierait les choses.
    Ça me semble effectivement la meilleure solution

    Citation Envoyé par DonQuiche Voir le message
    * Créer une CovariantList<T> héritant de List<T> mais déclarant T comme covariant (pas sûr que ce soit possible mais à tester)
    Non, pas possible... seule les interfaces et delegates peuvent être covariants. Et de toutes façons, dans une List<T>, T apparait en entrée et en sortie, donc il ne peut pas être variant

    Citation Envoyé par DonQuiche Voir le message
    * Créer un CovariantListWrapper<TSource, TDest> implémentant IList<TDest> et déclarant un constructeur prenant une IList<TSource> en argument.
    Même problème

  10. #10
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 493
    Points
    5 493
    Par défaut
    @Tomlev
    Ok pour la première solution mais la seconde ne pose aucun problème : elle ne repose pas sur la covariance/contravariance.

  11. #11
    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 DonQuiche Voir le message
    @Tomlev
    Ok pour la première solution mais la seconde ne pose aucun problème : elle ne repose pas sur la covariance/contravariance.
    Ah oui, j'avais mal compris ce que tu proposais. Il vaudrait mieux nommer la classe autrement d'ailleurs... par exemple AbstractingList<TConcrete, TAbstract>.

    En tous cas c'est effectivement une bonne idée ; voilà une implémentation basique :

    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
        public class AbstractingList<TConcrete, TAbstract> : IList<TAbstract>
            where TConcrete : TAbstract
        {
            private IList<TConcrete> _concreteList;
     
            public AbstractingList(IList<TConcrete> concreteList)
            {
                if (concreteList == null)
                    throw new ArgumentNullException("concreteList");
                _concreteList = concreteList;
            }
     
            #region Implementation of IEnumerable
     
            public IEnumerator<TAbstract> GetEnumerator()
            {
                return _concreteList.Cast<TAbstract>().GetEnumerator();
            }
     
            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }
     
            #endregion
     
            #region Implementation of ICollection<TAbstract>
     
            public void Add(TAbstract item)
            {
                _concreteList.Add((TConcrete)item);
            }
     
            public void Clear()
            {
                _concreteList.Clear();
            }
     
            public bool Contains(TAbstract item)
            {
                return _concreteList.Contains((TConcrete)item);
            }
     
            public void CopyTo(TAbstract[] array, int arrayIndex)
            {
                if (array == null)
                    throw new ArgumentNullException("array");
                if (arrayIndex < 0 || arrayIndex + _concreteList.Count > array.Length)
                    throw new ArgumentOutOfRangeException("arrayIndex");
     
                for (int i = 0; i < _concreteList.Count; i++)
                {
                    array[i] = _concreteList[i];
                }
            }
     
            public bool Remove(TAbstract item)
            {
                return _concreteList.Remove((TConcrete)item);
            }
     
            public int Count
            {
                get { return _concreteList.Count; }
            }
     
            public bool IsReadOnly
            {
                get { return _concreteList.IsReadOnly; }
            }
     
            #endregion
     
            #region Implementation of IList<TAbstract>
     
            public int IndexOf(TAbstract item)
            {
                return _concreteList.IndexOf((TConcrete)item);
            }
     
            public void Insert(int index, TAbstract item)
            {
                _concreteList.Insert(index, (TConcrete)item);
            }
     
            public void RemoveAt(int index)
            {
                _concreteList.RemoveAt(index);
            }
     
            public TAbstract this[int index]
            {
                get { return _concreteList[index]; }
                set { _concreteList[index] = (TConcrete)value; }
            }
     
            #endregion
        }

Discussions similaires

  1. [CSS] Problème d'espaces dans une liste
    Par sylsau dans le forum Mise en page CSS
    Réponses: 3
    Dernier message: 03/08/2006, 13h46
  2. Problème sur évènement d'une liste déroulante
    Par krfa1 dans le forum Access
    Réponses: 7
    Dernier message: 05/05/2006, 08h03
  3. Réponses: 17
    Dernier message: 03/05/2006, 14h01
  4. [vbnet] problème de conversion dans une datagrid
    Par Jsh dans le forum Windows Forms
    Réponses: 5
    Dernier message: 04/09/2005, 12h40
  5. Réponses: 4
    Dernier message: 16/06/2005, 15h37

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