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 :

Architecture générique et héritage


Sujet :

C#

  1. #1
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    novembre 2010
    Messages
    162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Conseil

    Informations forums :
    Inscription : novembre 2010
    Messages : 162
    Points : 156
    Points
    156
    Par défaut Architecture générique et héritage
    Bonjour,
    Je cherche à faire un supergénéric...
    Du code parlant plus facilement, GO :
    Code C# : 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
     
    // Eléments de structure
        public abstract class Identifier
        {
            // Identifiant dans la base de données
            public int ID { get; set; }
        }
     
        public abstract partial class NNLinkHistory<TIdentifierA, TIdentifierB> : IHistory
            where IdentifierA : Identifier
            where IdentifierB : Identifier
        {
            // Identifiant de la première entité
            public int Identifier1ID { get; set; }
     
            // Lien de navigation vers la première entité
            public TIdentifierA Identifier1 { get; set; }
     
            // Identifiant de la seconde entité
            public int Identifier2ID { get; set; }
     
            // Lien de navigation vers la seconde entité
            Public TIdentifierB Identifier2 { get; set; }
     
            // Date d'association (Interface IHistory)
            public DateTime AssociationDate { get; set; } = DateTime.UtcNow;
     
            // Date de dissociation (Interface IHistory)
            public DateTime? DissociationDate { get; set; }
        }
     
    // Objets utiles
        public class Object1 : Identifier
        {
            // V1
            public ICollection<O1O2H> Object2sV1 { get; set; } = new HashSet<O1O2H>();
            // V2
            public MyCollection<O1O2H> Object2sV2 { get; set; } = new MyCollection<O1O2H>();
        }
     
        public class Object2 : Identifier
        {
            // V1
            public ICollection<O1O2H> Object1sV1 { get; set; } = new HashSet<O1O2H>();
            // V2
            public MyCollection<O1O2H> Object1s { get; set; } = new MyCollection<O1O2H>();
        }
     
        public class O1O2H : NNLinkHistory<Object1, Object2>
        {
            public int OtherProperty{ get; set; }
        }

    Ceux qui utilise un ORM reconnaitront un lien 0,N---0,N entre 2 tables. D'ailleurs tant que j'y suis, je précise que j'utilise EFCore 3.1.17 et que je ne puis monter sur la version 5 car le framework utilisé est le standard 4.8 incompatible... no comment

    A cela, j'ai ajouté une méthode d'extension pour aller chercher la relation active
    Code C# : 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
     
        public static TEntity GetActive<TEntity>(this ICollection<TEntity> histories, BaseDbContext ctx)
            where TEntity : class, IHistory
        {
            public NNLinkHistory<TIdentifierA, TIdentifierB> GetActive(DbContext ctx, bool isForceToReload = false)
             {
                // Si l'historique n'est pas null
                if (this.Count() > 0 || !isForceToReload)
                    // Renvoyer l'historique
                    return this.First();
     
                // Récupérer la propriété à utiliser par son type
                var property = ctx.GetType()
                                  .GetProperties()
                                  .FirstOrDefault(o => o.PropertyType == typeof(DbSet<NNLinkHistory<TIdentifierA, TIdentifierB>>));
     
                // Si la propriété n'a pas été trouvée
                if (property == null)
                    // Générer une exception
                    throw new InvalidCastException();
     
                var queryable = (IQueryable<NNLinkHistory<TIdentifierA, TIdentifierB>>)property.GetValue(ctx);
     
                // Mettre à jour l'historique
                Clear();
     
                if (query.Count() > 0)
                    AddRange(query.ToList());
     
                // Renvoyer l'historique
                return this.OrderByDescending(o => o.AssociationDate).FirstOrDefault();
            }

    Ca fonctionne impeccable mais j'aimerais pouvoir faire un objet à part entière pour pouvoir hériter de cet objet afin de définir une fonction GetActive légèrement différente pour une classe particulière :
    Code C# : 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
     
        public class MyCollection<TNNLinkHistory> : List<TNNLinkHistory>
            where TNNLinkHistory : NNLinkHistory<TIdentifierA, TIdentifierB> // Là déjà l'IDE râle car il ne connait pas TIdentifierA et TIdentifierB
        {
            public NNLinkHistory<TIdentifierA, TIdentifierB> GetActive(DbContext ctx, bool isForceToReload = false)
             {
                // Si l'historique n'est pas null
                if (this.Count() > 0 || !isForceToReload)
                    // Renvoyer l'historique
                    return this.First();
     
                // Récupérer la propriété à utiliser par son type
                var property = ctx.GetType()
                                  .GetProperties()
                                  .FirstOrDefault(o => o.PropertyType == typeof(DbSet<NNLinkHistory<TIdentifierA, TIdentifierB>>));
     
                // Si la propriété n'a pas été trouvée
                if (property == null)
                    // Générer une exception
                    throw new InvalidCastException();
     
                var queryable = (IQueryable<NNLinkHistory<TIdentifierA, TIdentifierB>>)property.GetValue(ctx);
     
                // Mettre à jour l'historique
                Clear();
     
                if (query.Count() > 0)
                    AddRange(query.ToList());
     
                // Renvoyer l'historique
                return this.OrderByDescending(o => o.AssociationDate).FirstOrDefault();
            }
       }

    Mais là ça coince

    Bien évidemment, il n'y a pas que la fonction GetActive, il y a entre autre SetActive (qui s'appuie sur GetActive) mais seule celle-ci sera différente (d'où l'intérêt de l'héritage).

    Auriez-vous une idée ?

  2. #2
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    avril 2007
    Messages
    13 953
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : avril 2007
    Messages : 13 953
    Points : 24 634
    Points
    24 634
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    public class MyCollection<TNNLinkHistory, TIdentifierA, TIdentifierB> : List<TNNLinkHistory>
            where TNNLinkHistory : NNLinkHistory<TIdentifierA, TIdentifierB>
    y a déjà ca
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  3. #3
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    novembre 2010
    Messages
    162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Conseil

    Informations forums :
    Inscription : novembre 2010
    Messages : 162
    Points : 156
    Points
    156
    Par défaut
    Merci pour ta réponse Pol63,
    J'y avait bien pensé mais je trouvais ça ridicule de mettre les 3 génériques alors que les 2 autres sont dans le premier.
    De plus j'avais des erreurs de typage dans mes méthodes surchargées mais avec un peu de rigueur, de persévérance et d'essaye, j'ai un code qui compile. Suite dans quelques jours pour les essaye en utilisation...

    Il y a un autre moyen pour éviter de redire les types ? Juste avec <TNNLinkHistory> ?

  4. #4
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    novembre 2010
    Messages
    162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Conseil

    Informations forums :
    Inscription : novembre 2010
    Messages : 162
    Points : 156
    Points
    156
    Par défaut
    Bon, finalement, après avoir développé la méthode avec
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
        public class MyCollection<TNNLinkHistory, TIdentifierA, TIdentifierB> : List<TNNLinkHistory>
            where TNNLinkHistory : NNLinkHistory<TIdentifierA, TIdentifierB>, new()
            where TIdentifierA : Identifier
            where TIdentifierB : Identifier

    L'IDE ne me mentionne pas d'erreur mais je me suis dit qu'en fait, je n'avais pas besoin de mettre TNNLinkHistory, alors j'ai tenté sans :
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        public class MyCollection<TIdentifierA, TIdentifierB> : List<NNLinkHistory<TIdentifierA, TIdentifierB>>
            where TIdentifierA : Identifier
            where TIdentifierB : Identifier

    Après quelques adaptations niveau code, l'IDE ne me mentionne pas d'erreur... Affaire à suivre (à tester)...

Discussions similaires

  1. Méthode générique et héritage
    Par Clarkgbl dans le forum C#
    Réponses: 4
    Dernier message: 05/09/2012, 18h04
  2. [Security] Poincut type générique et héritage
    Par bilgetz dans le forum Spring
    Réponses: 4
    Dernier message: 23/05/2012, 12h59
  3. Classe générique et héritage
    Par Picolo18 dans le forum Langage
    Réponses: 17
    Dernier message: 14/12/2008, 14h17
  4. type générique avec héritage multiple
    Par apqmwnqmap dans le forum Langage
    Réponses: 4
    Dernier message: 13/03/2008, 14h56
  5. Héritage de package génériques
    Par AlienAttack2k dans le forum Ada
    Réponses: 1
    Dernier message: 23/07/2007, 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