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

 .NET Discussion :

Nouvelle méthode extension FirstOrNew - problème new type inconnu


Sujet :

.NET

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2012
    Messages
    233
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2012
    Messages : 233
    Points : 92
    Points
    92
    Par défaut Nouvelle méthode extension FirstOrNew - problème new type inconnu
    Bonjour,

    Maintenant, je cherche à coder la méthode d'extension qui cherche dans une liste de type T (car on sait pas encore quel type) puis renvoie le 1er élément de la liste si la liste contient qqe chose ou crée un élément sinon.

    Pour le moment j'ai codé ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public static IEnumerable<T> FirstOrNew(this IEnumerable<T> Lists, Func<T, var> selector)
            {
                if (Lists == null)
                {
                    return new T; 
                }
                else
                {
                    return Lists.First(); 
                }
            }
    J'ai encore des problèmes car je vois pas comment coder le new T. J'imagine que c'est pas bon, confirmé par du rouge dessous, mais je vois pas la syntaxe pour le remplacer étant donné qu'on ne connait pas encore son type.

    Quelqu'un pourrait me filer un coup de main?

    Merci d'avance!

  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 : 42
    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 749
    Points
    39 749
    Par défaut
    C'est presque ça, mais il faut déclarer T comme un paramètre de type générique, et lui mettre la contrainte new()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
            public static IEnumerable<T> FirstOrNew<T>(this IEnumerable<T> list)
                where T : new()
            {
                if (list == null)
                {
                    return new T(); 
                }
                else
                {
                    return list.First(); 
                }
            }
    (j'ai enlevé le paramètre selector vu que tu ne l'utilisais pas...)

  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 : 42
    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 749
    Points
    39 749
    Par défaut
    Par contre attention : avec ce code, ça va planter si la liste n'est pas nulle mais qu'elle est vide...

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2012
    Messages
    233
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2012
    Messages : 233
    Points : 92
    Points
    92
    Par défaut
    Merci Tomlev!!!

    Par contre, liste nulle est différent de liste vide?
    Quelle est la syntaxe pour dire qu'une liste est vide?

    D'ailleurs sur le bout de programme que tu m'as donné, on me demande un cast sur new T()?

  5. #5
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    list.Length == 0 ou list.Count == 0 si je ne m'abuse
    On ne jouit bien que de ce qu’on partage.

  6. #6
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Par contre, j'ai une question...

    Si j'ai une classe "Person" avec pour unique constructeur "Person(int id, string name)"

    Comment ça peut marcher ?

    Il va automatiquement créer un new Person(0, string.Empty) ? (Valeurs par défaut de ces deux types de valeur lorsqu'ils ne sont pas initialisés si je ne m'abuse.
    On ne jouit bien que de ce qu’on partage.

  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 : 42
    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 749
    Points
    39 749
    Par défaut
    Citation Envoyé par bilou_12 Voir le message
    Par contre, liste nulle est différent de liste vide?
    une "liste nulle" (c'est un abus de langage), c'est une absence de liste (l'objet liste n'existe pas)

    Une liste vide, c'est un objet liste qui existe, mais qui contient 0 élément.

    Citation Envoyé par bilou_12 Voir le message
    Quelle est la syntaxe pour dire qu'une liste est vide?
    cf. la réponse de StringBuilder, mais je vais y revenir...

    Citation Envoyé par bilou_12 Voir le message
    D'ailleurs sur le bout de programme que tu m'as donné, on me demande un cast sur new T()?
    En fait c'est le type de retour qui n'est pas bon : si tu veux récupérer un élément de la liste, le type de retour devrait être T et non pas IEnumerable<T>
    Citation Envoyé par StringBuilder Voir le message
    list.Length == 0 ou list.Count == 0 si je ne m'abuse
    .Count en effet pour une liste, sauf qu'en l'occurrence, c'est un IEnumerable<T>, pas une IList<T>...

    La solution pour tester si un IEnumerable<T> est vide est d'utiliser la méthode d'extension Any() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if (!list.Any())
    {
        // liste vide
    }
    Le problème, c'est qu'on veut ensuite récupérer le premier élément si la liste n'est pas vide. Et si on appelle Any(), puis First(), on déclenche 2 fois l'énumération de la collection. Si c'est par exemple une liste en mémoire, ce n'est pas gênant, mais si c'est par exemple une requête Linq to Entities, c'est plus gênant car ça va réexécuter la requête SQL correspondante.

    On ne peut pas non plus utiliser FirstOrDefault() pour vérifier que la liste est vide : si T est un type valeur, FirstOrDefault() ne renverra pas null, donc on ne pourra pas savoir si la liste était vide ou si la valeur renvoyée fait vraiment partie de la liste.

    La solution est de manipuler directement l'énumérateur :

    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
            public static T FirstOrNew<T>(this IEnumerable<T> list)
                where T : new()
            {
                if (list != null)
                {
                    using (var enumerator = list.GetEnumerator())
                    {
                        if (enumerator.MoveNext())
                        {
                            return enumerator.Current;
                        }
                    }
                }
                return new T(); 
            }
    Citation Envoyé par StringBuilder Voir le message
    Si j'ai une classe "Person" avec pour unique constructeur "Person(int id, string name)"

    Comment ça peut marcher ?

    Il va automatiquement créer un new Person(0, string.Empty) ? (Valeurs par défaut de ces deux types de valeur lorsqu'ils ne sont pas initialisés si je ne m'abuse.
    Non, la contrainte new() impose l'existence d'un constructeur public sans paramètre. Il n'est malheureusement pas possible de spécifier les paramètres dans la contrainte.

    cf. cette discussion pour plus de détails

    (et string est un type référence, donc sa valeur par défaut n'est pas String.Empty mais null...)

  8. #8
    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 : 37
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Points : 8 080
    Points
    8 080
    Par défaut
    Connaissez vous DefaultIfEmpty() ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    public static T FirstOrNew<T>(this IEnumerable<T> list, T defaultValue)
    {
        return list.DefaultIfEmpty(defaultValue).First();
    }
    public static T FirstOrNew<T>(this IEnumerable<T> list, Func<T,bool> predicate, T defaultValue)
    {
        return list.Where(predicate).DefaultIfEmpty(defaultValue).First();
    }
    ou

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    public static T FirstOrNew<T>(this IEnumerable<T> list) where T:new()
    {
        return list.DefaultIfEmpty(new T()).First();
    }
    public static T FirstOrNew<T>(this IEnumerable<T> list, Func<T,bool> predicate) where T:new()
    {
        return list.Where(predicate).DefaultIfEmpty(new T()).First();
    }
    ou encore:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    public static T FirstOrNew<T>(this IEnumerable<T> list, Func<T> factory)
    {
        return list.DefaultIfEmpty(factory()).First();
    }
    public static T FirstOrNew<T>(this IEnumerable<T> list, Func<T,bool> predicate, Func<T> factory)
    {
        return list.Where(predicate).DefaultIfEmpty(factory()).First();
    }
    Les possibiltés sont infinies

  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 : 42
    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 749
    Points
    39 749
    Par défaut
    Citation Envoyé par Nathanael Marchand Voir le message
    Connaissez vous DefaultIfEmpty() ?
    Oui mais DefaultIfEmpty ça colle pas par rapport à ce qu'il veut faire :
    - ça n'accepte pas une séquence nulle
    - ça renvoie la valeur par défaut (null pour un type référence), alors que le PO veut créer une instance de T

  10. #10
    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 : 37
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Points : 8 080
    Points
    8 080
    Par défaut
    Citation Envoyé par tomlev Voir le message
    Oui mais DefaultIfEmpty ça colle pas par rapport à ce qu'il veut faire :
    - ça n'accepte pas une séquence nulle
    - ça renvoie la valeur par défaut (null pour un type référence), alors que le PO veut créer une instance de T
    Ben si ca colle, ca renvoit null si tu lui dis de renvoyer null, si tu lui précises quoi renvoyer ca marche. Dans mon deuxieme exemple ca le fait exactement, dans le troisième tu peux même passer une factory de T
    Et pour la séquence nulle, aucune méthode linq ne marche si l'enumerable en question est nul. Ce qui est logique!
    Ca serait assez perturbant de pouvoir faire ceci (même si méthode d'extension=sucre syntaxique):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ((MonType)null).MaMethode();

  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 : 42
    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 749
    Points
    39 749
    Par défaut
    Citation Envoyé par Nathanael Marchand Voir le message
    Et pour la séquence nulle, aucune méthode linq ne marche si l'enumerable en question est nul. Ce qui est logique!
    Bah ça semble logique dans la mesure où les méthodes d'extension s'utilisent comme des méthodes d'instance, mais justement ce n'est pas des méthodes d'instance... je profite souvent de ça pour pouvoir justement les appeler sur des valeurs qui peuvent être nulles. Par exemple j'ai une méthode EmptyIfNull(), qui fait précisément ce que son nom indique...

    Citation Envoyé par Nathanael Marchand Voir le message
    Ca serait assez perturbant de pouvoir faire ceci (même si méthode d'extension=sucre syntaxique):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ((MonType)null).MaMethode();
    Apparemment ça perturbe un peu le compilateur en tous cas, il génère un warning sur ce code...
    https://connect.microsoft.com/Visual...ension-methods
    (enfin pas exactement sur ce code, mais si tu fais default(MonType).MaMethode())

Discussions similaires

  1. Réponses: 2
    Dernier message: 06/05/2014, 10h51
  2. méthode de type inconnue
    Par robert_trudel dans le forum Qt
    Réponses: 2
    Dernier message: 27/09/2006, 11h34
  3. Réponses: 4
    Dernier message: 30/01/2005, 14h23
  4. [Sybase] Problème de type sous ASE
    Par Hotchotte dans le forum Sybase
    Réponses: 1
    Dernier message: 18/12/2004, 11h04
  5. Fonction divisant argument de type inconnu
    Par Nasky dans le forum C
    Réponses: 9
    Dernier message: 29/07/2003, 00h32

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