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 :

Multiples "paramètres" dans une expression lambda


Sujet :

C#

  1. #1
    Membre averti
    Inscrit en
    Août 2011
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 16
    Par défaut Multiples "paramètres" dans une expression lambda
    Bonjour,

    Context :
    Nous avons un objet écrit par nos soins se chargeant de faire la pagination / sort / filtre sur une table.
    Celui-ci est de type Table<T> where T : Interface.
    Ce qui nous permet d'obtenir toujours les mêmes tables mais typées selon le type d'objet qu'elle contient.

    Nous aimerions (afin de nous faciliter la tâche dans les différentes vues (ASP.NET MVC 3)) pouvoir écrire quelque chose comme :

    @Html.Table(LaTable, table => ElementDeLaTable.Property1, ElementDeLaTable.Property2).

    Cet appel aurait pour but de créer la table (en html) en fonction des différentes propriétés passées par l'expression lambda.

    Malheureusement, nous ne somme pas encore arrivés à écrire l'expression pour qu'elle accepte plusieurs paramètres comme cités ci-dessus.

    En plus de cela, il faudrait que l'expression lambda connaisse le type T de la table afin de pouvoir acceder aux différentes propriétés du type.

    Quelqu'un aurait-il des conseils / examples sur la façon de procéder ?

    Oui, ce post pourrait-être dans la section Développement Web puisqu'il s'agit de produire un output web, mais l'intention reste les expressions lambdas.

    Merci pour votre aide.

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

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Octobre 2008
    Messages : 847
    Par défaut
    Bonjour,

    Bon j'ai pas tout suivi de la demande, donc je répondrais uniquement sur ce que je sais, comment écrire une expression lambda à plusieurs paramètres, avec un exemple (totalement bidon) concaténant les résultats d'une "requête" en vue d'un affichage (voir la documentation de Aggregate):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var query = //... query est un IEnumerable
     
    string output = 
        query
        .Aggregate (
            New StringBuilder (),
            (state, current) => state.Append (current), // c'est ici que cela te concerne
            finalState => finalState.ToString()
        );
    Cordialement !

  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
    Par défaut
    C'est un truc comme ça que tu veux ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
        public static void Table<T>(this HtmlHelper helper, Table<T> table, params Expression<Func<T, object>>[] propertySelectors)
        {
            foreach (var selector in propertySelectors)
            {
                var expr = selector.Body as MemberExpression;
                if (expr == null)
                    throw new ArgumentException("The body must be a member access expression");
                string propertyName = expr.Member.Name;
     
                ...
            }
        }
    En fait, si j'ai bien compris ton histoire, tu n'as pas besoin d'une expression lambda à plusieurs paramètres, mais de plusieurs paramètres de type expression lambda...

  4. #4
    Membre averti
    Inscrit en
    Août 2011
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 16
    Par défaut
    C'est exactement ca que je cherchais, merci pour vos réponses.

    En effet, après y avoir réfléchi, ce n'est pas une expression lambda avec plusieurs paramètres, mais plusieurs expressions lambda.

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

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Octobre 2008
    Messages : 847
    Par défaut
    bon ben moi j'avais rien compris tant pis, toute information peut toujours rester utile

    Cordialement !

  6. #6
    Membre averti
    Inscrit en
    Août 2011
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 16
    Par défaut
    Une question reste en suspend :

    Comment appeler ce helper puisque je n'ai rien sur quoi basé mon expression lambda (ou alors j'ai raté quelque chose).

    Pour l'appeler je devrais faire quelque chose comme :

    @Html.Table(table, ??? => ???.???, ??? => ???.???)

    Ma table contient elle-même une liste de type<T> d'élément et c'est mon helper qui parcourt cette liste pour en récupérer le displayname et sa valeur.

    Une idée ? (J'ai comme une impression de pas être clair du tout sur ce coup la ...)

    EDIT :

    Je suis parvenu à l'utiliser avec 1 expression :
    @Html.Table(Model, Person => Person.FullName)

    Mais comment passer une deuxième expression ?

    Quand je fais :

    @Html.Table(Model, Person => Person.FullName, Person => Person.LastMembershipApproval)

    La deuxième expression lance une exception comme quoi le field n'existe pas.

    Une idée ?

    EDIT 2 :

    Il semblerait que ca passe, mais uniquement avec des property de type string. Quelqu'un pourrait m'expliquer pourquoi ?

    Merci bien.

  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
    Par défaut
    Citation Envoyé par Ragnarock Voir le message
    @Html.Table(Model, Person => Person.FullName, Person => Person.LastMembershipApproval)

    La deuxième expression lance une exception comme quoi le field n'existe pas.
    Citation Envoyé par Ragnarock Voir le message
    Il semblerait que ca passe, mais uniquement avec des property de type string. Quelqu'un pourrait m'expliquer pourquoi ?
    Sans voir ton code ça va être difficile... en tous cas dans le code que je t'ai donné il n'y a rien qui puisse causer ce genre d'erreur

  8. #8
    Membre averti
    Inscrit en
    Août 2011
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 16
    Par défaut
    Voila le 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
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    public static MvcHtmlString TableContent<T>(this HtmlHelper helper, Table<T> table, params Expression<Func<T, object>>[] predicate) where T : IAuditedObject
            {
                StringBuilder sb = new StringBuilder();
                ICollection<string> properties = new List<string>();
                sb.AppendLine("<div class=\"table-body\">");
                sb.AppendLine("<table>");
                sb.AppendLine("<thead>");
                sb.AppendLine("<tr>");
                Type type = typeof(T);
                foreach (var selector in predicate)
                {
                    var expr = selector.Body as MemberExpression;
                    if (expr == null)
                        throw new ArgumentException("The body must be a member access expression");
                    string propertyName = expr.Member.Name;
                    sb.AppendLine("<th>" + propertyName + "</th>");
                    properties.Add(propertyName);
                }
                sb.AppendLine("</tr>");
                sb.AppendLine("</thead>");
                sb.AppendLine("<tbody>");
                foreach (var element in table.ShowedItems)
                {
                    sb.AppendLine("<tr>");
                    foreach (var prop in properties)
                    {
                        sb.AppendLine("<td>" + type.GetProperty(prop).GetValue(element, null) + "</td>");
                    }
                    sb.AppendLine("</tr>");
                }
                sb.AppendLine("</tbody>");
                sb.AppendLine("</table>");
                sb.AppendLine("</div>");
                return MvcHtmlString.Create(sb.ToString());
            }
    Et la classe Person :

    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
     
     public class Person : IAuditedObject
        {
            public int Id { get; set; }
            public int? AddrId { get; set; }
     
            [DisplayName("First Name")]
            [StringLength(100)]
            [Required]
            public string FirstName { get; set; }
     
            [DisplayName("Last Name")]
            [StringLength(100)]
            [Required]
            public string LastName { get; set; }
     
            [StringLength(6)]
            public string Initials { get; set; }
     
            [DisplayName("Title")]
            public int? TitleId { get; set; }
            public virtual PersonTitle Title { get; set; }
     
            [DisplayName("Sites")]
            public virtual ICollection<PersonSite> Sites { get; set; }
     
            [DisplayName("Last Membership Approval")]
            public Nullable<DateTime> LastMembershipApproval { get; set; }
     
            [DisplayName("Active")]
            public bool IsActive { get; set; }
     
            ...
    }
    Si jamais quelqu'un a une idée...

  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
    Par défaut
    Ca semble pourtant correct... quelle est l'exception exacte (type, message et stacktrace), et sur quelle ligne se produit-elle ?

    (soit dit en passant, le nom de ton paramètre "predicate" est un peu foireux... un prédicat, c'est une fonction qui renvoie true ou false, donc rien à voir avec ce que tu fais)

  10. #10
    Membre averti
    Inscrit en
    Août 2011
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 16
    Par défaut
    Exact pour le nom de le la fonction, c'était un prédicat à l'origine, je ne l'ai pas changé

    L'exception lancée est l'exception lancée dans le cas ou expr == null.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    var expr = selector.Body as MemberExpression;
                    if (expr == null)
                        throw new ArgumentException("The body must be a member access expression");

    Stack trace :

    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
    [ArgumentException: The body must be a member access expression]
       EORTC.TOOLS.EORTCPaginationHelper.EORTCTableContent(HtmlHelper helper, EORTCPaginatedTable`1 table, Expression`1[] predicate) in C:\Projects\_Prisma\EORTC.TOOLS\Tables\EORTCPaginationHelper.cs:61
       EORTC.TOOLS.EORTCPaginationHelper.EORTCTable(HtmlHelper helper, String action, String controller, EORTCPaginatedTable`1 table, String method, Expression`1[] predicate) in C:\Projects\_Prisma\EORTC.TOOLS\Tables\EORTCPaginationHelper.cs:174
       ASP._Page_Views_Person__Index_cshtml.Execute() in c:\Projects\_Prisma\Prisma.Web\Views\Person\_Index.cshtml:7
       System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +272
       System.Web.Mvc.WebViewPage.ExecutePageHierarchy() +81
       System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) +187
       System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance) +220
       System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer) +115
       System.Web.Mvc.HtmlHelper.RenderPartialInternal(String partialViewName, ViewDataDictionary viewData, Object model, TextWriter writer, ViewEngineCollection viewEngineCollection) +279
       System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial(HtmlHelper htmlHelper, String partialViewName, Object model) +72
       ASP._Page_Views_Person_Index_cshtml.Execute() in c:\Projects\_Prisma\Prisma.Web\Views\Person\Index.cshtml:10
       System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +272
       System.Web.Mvc.WebViewPage.ExecutePageHierarchy() +81
       System.Web.WebPages.StartPage.RunPage() +58
       System.Web.WebPages.StartPage.ExecutePageHierarchy() +94
       System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) +173
       System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance) +220
       System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer) +115
       System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context) +303
       System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) +13
       System.Web.Mvc.<>c__DisplayClass1c.<InvokeActionResultWithFilters>b__19() +23
       System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +260
       System.Web.Mvc.<>c__DisplayClass1e.<InvokeActionResultWithFilters>b__1b() +19
       System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) +177
       System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +343
       System.Web.Mvc.Controller.ExecuteCore() +116
       System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +97
       System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +10
       System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +37
       System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +21
       System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +12
       System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
       System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +50
       System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f) +7
       System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) +22
       System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +60
       System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
       System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8963149
       System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +184

  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
    Par défaut
    Ah ok, je vois quel est le problème... comme l'expression est déclarée comme étant de type Func<T, object>, ça marche bien pour les types référence qui sont directement convertibles en object (conversion de référence), mais pas pour les types valeur à cause du boxing : l'expression contient en fait une conversion en object (implicite au niveau du code). Il faut donc tenir compte de ce cas :

    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
            foreach (var selector in propertySelectors)
            {
                selector.Dump();
                var expr = selector.Body;
                if (expr.NodeType == ExpressionType.Convert && expr.Type == typeof(object))
                    expr = ((UnaryExpression)expr).Operand;
                var memberExpr = expr as MemberExpression;
                if (memberExpr == null)
                    throw new ArgumentException("The body must be a member access expression");
                string propertyName = memberExpr.Member.Name;
     
     
                ...
     
            }

  12. #12
    Membre averti
    Inscrit en
    Août 2011
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Août 2011
    Messages : 16
    Par défaut
    Merci beaucoup pour ton aide et pour l'explication. Ce soir, je m'endormirai moins bète ...

    Je "resolve" le topic.
    Merci beaucoup

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

Discussions similaires

  1. [Débutant] passer d'un tableau à une liste dans une expression lambda
    Par Hepil dans le forum Linq
    Réponses: 8
    Dernier message: 25/06/2013, 17h23
  2. [RegEx] Simple ou double quote dans une expression régulière
    Par Khleo dans le forum Langage
    Réponses: 2
    Dernier message: 27/12/2010, 15h58
  3. Réponses: 2
    Dernier message: 09/08/2010, 15h41

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