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

VB.NET Discussion :

[LINQ] Paramètre ByRef dans une query LINQ : problème


Sujet :

VB.NET

  1. #1
    Expert confirmé
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    Par défaut [LINQ] Paramètre ByRef dans une query LINQ : problème
    Hello,

    Sur le projet qui m'occupe actuellement, j'ai besoin de faire ceci :
    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
        Public Sub CheckForDuplicateSeason(ByRef detailsOwn As List(Of PROMO_DTO.PromoDetailOwn), Optional ByRef detailsDept As List(Of PROMO_DTO.PromoDetailDepartment) = Nothing)
            If detailsDept Is Nothing Then
                Dim data = (From d1 As PROMO_DTO.PromoDetailOwn In detailsOwn
                            From d2 As PROMO_DTO.PromoDetailOwn In detailsOwn
                            Where d1 IsNot d2 And d1.Seasons.Intersect(d2.Seasons).Count > 0
                            Select d1)
     
                For Each d As PROMO_DTO.PromoDetailOwn In data.ToList
                    d.ErrorText = "saison"
                Next
            Else
                Dim data = (From d1 As PROMO_DTO.PromoDetailOwn In detailsOwn
                            From d2 As PROMO_DTO.PromoDetailDepartment In detailsDept
                            Where d1.Seasons.Intersect(d2.Seasons).Count > 0
                            Select d1)
     
                For Each d As PROMO_DTO.PromoDetailOwn In data.ToList
                    d.ErrorText = "saison"
                Next
            End If
        End Sub
    En l'état, VS me fait la gueule et souligne, dans les deux branches du If, la source de la 2e liste de ma query sous prétexte que c'est un paramètre ByRef. Or la source de la première ligne l'est tout autant (surtout qu'il s'agit de la même liste dans le premier cas).

    En soit, ce n'est pas bien grave, je peux faire comme indiquer dans la MSDN et modifier mon code comme suit :
    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 Sub CheckForDuplicateSeason(ByRef detailsOwn As List(Of PROMO_DTO.PromoDetailOwn), Optional ByRef detailsDept As List(Of PROMO_DTO.PromoDetailDepartment) = Nothing)
            Dim dto As List(Of PROMO_DTO.PromoDetailOwn) = detailsOwn
            If detailsDept Is Nothing Then
                Dim data = (From d1 As PROMO_DTO.PromoDetailOwn In detailsOwn
                            From d2 As PROMO_DTO.PromoDetailOwn In detailsOwn
                            Where d1 IsNot d2 And d1.Seasons.Intersect(d2.Seasons).Count > 0
                            Select d1)
     
                For Each d As PROMO_DTO.PromoDetailOwn In data.ToList
                    d.ErrorText = "saison"
                Next
            Else
                Dim ddp As List(Of PROMO_DTO.PromoDetailDepartment) = detailsDept
                Dim data = (From d1 As PROMO_DTO.PromoDetailOwn In detailsOwn
                            From d2 As PROMO_DTO.PromoDetailDepartment In detailsDept
                            Where d1.Seasons.Intersect(d2.Seasons).Count > 0
                            Select d1)
     
                For Each d As PROMO_DTO.PromoDetailOwn In data.ToList
                    d.ErrorText = "saison"
                Next
            End If
        End Sub
    Mais j'aimerais bien comprendre le pourquoi malgré tout. Il doit sûrement y avoir une très bonne raison derrière tout ça mais avec le peu d'info que j'ai, cette erreur n'a aucune raison d'être...
    Kropernic

  2. #2
    Expert confirmé
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    Par défaut Ca maaaaaaarche !
    Bon... Je vois 3 possibilité...


    1. J'ai rien compris et j'ai eu un gros coup de bol
    2. La MSDN raconte des conneries
    3. Y a un sûût dans le framework


    D'après cette page, il m'aurait fallu :
    • Pour le framework 4.5 : créer une classe implémentant IEqualityComparer(Of Season) (Mais où ? Dans le projet qui abrite la classe Season ou dans le projet où je fais la comparaison ?)
    • Pour le framework 4 : que ma classe Season implémente IEquatable(Of Season).


    J'ai tenté la première option, rien à faire... (ou alors, voir option 1 du début).
    J'ai tenté la seconde option et bingo, ça marque du premier coup.

    C'est grave docteur ?
    Kropernic

  3. #3
    Membre chevronné
    Avatar de Sehnsucht
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Octobre 2008
    Messages
    847
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Lot et Garonne (Aquitaine)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Octobre 2008
    Messages : 847
    Points : 2 209
    Points
    2 209
    Par défaut
    Question bête ; une utilité concrète avoir mis les paramètres ByRef à la base (parce que c'est surtout ça qui pose problème) ?
    Nous sommes tous plus ou moins geek : ce qui est inutile nous est parfaitement indispensable ( © Celira )
    À quelle heure dormez-vous ?
    Censément, quelqu'un de sensé est censé s'exprimer sensément.

  4. #4
    Expert confirmé
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    Par défaut
    Citation Envoyé par Sehnsucht Voir le message
    Question bête ; une utilité concrète avoir mis les paramètres ByRef à la base (parce que c'est surtout ça qui pose problème) ?
    Bah pour pouvoir modifier leur contenu et conserver les modifs en sortie de sub.

    Mais ta remarque me fait me demander si le fait que ce soit des classes custom (et donc des types par référence) ne fait pas le taff déjà à la base...
    Kropernic

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    en byval ca gardera aussi le contenu modifié
    byref est utile pour les types par valeur pour propager les modifications
    pour les types par référence byref sert à changer la référence

    genre si dans la sub tu dis param2 = new list() avec byref l'appelant aura le new list
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  6. #6
    Expert confirmé
    Avatar de Kropernic
    Homme Profil pro
    Analyste / Programmeur / DBA
    Inscrit en
    Juillet 2006
    Messages
    3 932
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Analyste / Programmeur / DBA
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 932
    Points : 4 239
    Points
    4 239
    Par défaut
    Ah bin voilà.

    Malgré tout, pour ma culture général, qu'est-ce qui dérange dans le fait d'avoir un paramètre byref dans une query linq ?
    Kropernic

  7. #7
    Membre chevronné
    Avatar de Sehnsucht
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Octobre 2008
    Messages
    847
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Lot et Garonne (Aquitaine)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Octobre 2008
    Messages : 847
    Points : 2 209
    Points
    2 209
    Par défaut
    Le fait que justement, on ne pourrait pas réassigner cette variable (ou plutôt que cette réassignation ne se répercuterait pas).

    Lorsque on a un argument ByRef on "transmet" le message "on peut réassigner cet argument et ce changement sera visible de l'extérieur" soit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Dim foo As New Foo
    '...
    Sub ChangeFoo (ByRef arg As Foo)
        arg = New Foo ' modification répercutée sur "foo initial"
    End Sub
    Or dans la manière dont sont implémentées les lambdas (et leur closures) cet argument deviendrait un champ d'une classe, et la réassignation de ce champ ne se répercutera pas sur la variable initiale ayant servie à l'appel.
    C'est à dire qu'une lambda de ce type Dim changer = Sub () foo = New Foo sera grosso-modo transformée en :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Class Closure ' en réalité c'est un nom généré
        Public local_foo As Foo
     
        Public Sub New (foo As Foo)
            local_foo = foo
        End Sub
     
        Public Sub Invoke ()
            local_foo = New Foo ' ne se répercute pas sur le "foo initial"
        End Sub
    End Class
    Quant au pourquoi l'erreur n'est signalée qu'au "deuxième From" c'est parce qu'au premier From la lambda ne capture aucun argument ByRef donc en fait, le problème est signalé dès que l'argument ByRef se retrouve "dans une lambda"

    exemples (source est l'argument ByRef) :
    Quand on écrit From item In source c'est transformé en source.Select (Function (item) item) on voit bien que la lambda ne capture pas d'élement ByRef, donc aucun problème.
    Par contre quand on écrit From item1 In source From item2 In source c'est transformé en source.SelectMany (Function (item1) source, Function (item1, item2) New With { Key item1, Key item2 }) là source est bien capturé par la lambda d'où le problème.
    On aurait exactement le même type de souci tout en ayant "qu'un seul From" avec ceci par exemple From item In source Select (source) qui se voit donc transformé en source.Select (Function (item) source)

    Edit: à propos de quand utiliser ByVal/ByRef ; Pol63 a résumé ma pensée ; j'ajouterais juste que dans 90% des cas ByVal convient et l'utilisation de ByRef reste assez anecdotique (sans doute une des raisons qui ont fait que ByVal est désormais optionnel à préciser car c'est le choix par défaut).

    Edit bis: quelque remarques qui sont moins en rapport avec le sujet ; évite les .Count > 0 surtout quand il s'agit d'IEnumerable ça t'oblige à parcourir toute la collection alors que ce qui t'intéresse c'est de savoir s'il y en a au moins un du coup remplace par .Any ; dans le même ordre d'idée faire un .ToList au moment du ForEach n'apporte absolument rien
    Après on peut "a priori" réduire un peu la duplication du code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Public Sub CheckForDuplicateSeason(detailsOwn As List(Of PROMO_DTO.PromoDetailOwn), Optional detailsDept As List(Of PROMO_DTO.PromoDetailDepartment) = Nothing)
        ' à remplacer par un If classique pour ceux qui préfèrent
        Dim query = If (detailsDept Is Nothing,
                        From d1 In detailsOwn, d2 In detailsOwn
                        Where d1 IsNot d2 AndAlso d1.Seasons.Intersect (d2.Seasons).Any
                        Select d1,
                        From d1 In detailsOwn, d2 In detailsDept
                        Where d1.Seasons.Intersect (d2.Seasons).Any
                        Select d1)
     
        For Each d In query
            d.ErrorText = "saison"
        Next
    End Sub
    Nous sommes tous plus ou moins geek : ce qui est inutile nous est parfaitement indispensable ( © Celira )
    À quelle heure dormez-vous ?
    Censément, quelqu'un de sensé est censé s'exprimer sensément.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 10
    Dernier message: 09/03/2012, 15h38
  2. Colle sur un tri dans une requête linq to sql
    Par boby62423 dans le forum Linq
    Réponses: 5
    Dernier message: 18/03/2009, 10h01
  3. [2.2.0]Redondance de paramètres dans une Query
    Par lazarel dans le forum BIRT
    Réponses: 3
    Dernier message: 18/07/2007, 11h16
  4. [MySQL] menu select dans une page include problème de paramètres
    Par starr dans le forum PHP & Base de données
    Réponses: 8
    Dernier message: 07/07/2006, 08h42

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