Calendrier

Décembre 2009
L M M J V S D
  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      
<< < > >>

Présentation

Recherche

W3C

  • Flux RSS des articles

Linq To Objects

[C# 3.0] - Func<>

1 - on crée une expression lambda
            Func<int, int, int> f1;
            f1 = (x, y) => x * 10 + y;
 
 2 – Compilation
à partir de l'expression lambda est généré une méthode anonyme
LambdaExpression > Methode anonyme
 
           
            Func<int, int, int> f1 = delegate(int x, int y)
            {
                return (x * 10) + y;
            };
 
 
ce sont le nombre et le type des paramètres passés à la méthode anonyme qui determinent la signature de Func utilisée
-    parametres > nb + type
-    notion operation/expression
3 – Compilation (suite)
à partir de a méthode anonyme est générée par le compilateur une méthode statique
Methode anonyme > methode static
(non imbriquée dans le corps d'une méthode comme ici c'était le cas dans button_Click)
        [CompilerGenerated]
        private static int <button1_Click>b__1(int x, int y)
        {
            return ((x * 10) + y);
        }
 
4 - Signatures de Func<>
public delegate TResult Func<TResult>();
public delegate TResult Func<TArg0, TResult>(TArg0 arg0);
public delegate TResult Func<TArg0, TArg1, TResult>(TArg0 arg0, TArg1 arg1);
public delegate TResult Func<TArg0, TArg1, TArg2, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2);
public delegate TResult Func<TArg0, TArg1, TArg2, TArg3, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3);
 
Par Romagny13
Ecrire un commentaire - Voir les commentaires - Recommander
   [LINQ]  3 écritures equivalentes
  

J’utilises ma “classique” classe Contact contenant plusieurs properties(ContactName,ContactAge,etc.) et une liste générique de contacts LstContacts
           // 1 requête Linq
            var Query =
                from c in LstContacts
                where c.ContactName.StartsWith("A")
                select c;
            // 2 avec expressions lambdas
            IEnumerable<Contact> Query =
                LstContacts.Where(c => c.ContactName.StartsWith("A"))
                .OrderBy(c => c.ContactName)
                 .Select((Contact c) => c);
 
            // 3 avec les méthodes anonymes
            IEnumerable<Contact> Query = this.LstContacts.Where<Contact>(delegate(Contact c)
            {
                return c.ContactName.StartsWith("A");
            }).OrderBy<Contact, string>(delegate(Contact c)
            {
                return c.ContactName;
            }).Select<Contact, Contact>(delegate(Contact c)
            {
                return c; 
            });
 
Note : les "clauses" Select pour le 2 (avec expressions lambdas) et 3 (avec méthodes anonymes) sont "facultatives", on peut ne pas les mettre . Ce qui donnerait donc plus simplement
 
            // 2 avec expressions lambdas
            IEnumerable<Contact> Query =
                LstContacts.Where(c => c.ContactName.StartsWith("A"))
                .OrderBy(c => c.ContactName);
 
            // 3 avec les méthodes anonymes
            IEnumerable<Contact> Query = this.LstContacts.Where<Contact>(delegate(Contact c)
            {
                return c.ContactName.StartsWith("A");
            }).OrderBy<Contact, string>(delegate(Contact c)
            {
                return c.ContactName;
            });
 
Finalement si on veut tout bien mettre cela donnerait par exemple avec les expressions lambdas
 IEnumerable<Contact> Query =
                LstContacts.Where<Contact>(c => c.ContactName.StartsWith("A"))
                .OrderBy<Contact, string>(c => c.ContactName)
                .Select<Contact, Contact>((Contact c) => c);
 
Meme si on veut être tordu on fait des mélanges :p
IEnumerable<Contact> Query =
              from c in LstContacts.Where(c => c.ContactName.StartsWith("A")).OrderBy( c => c.ContactName)
              select c; 
// ou encore
IEnumerable<Contact> Query =
              from c in LstContacts.Where(delegate(Contact c)
              {
                  return c.ContactName.StartsWith("A");
              }
                  ).OrderBy(c => c.ContactName)
              select c;
 
Personnellement lorsque j’aurais été plus en profondeur dans la compréhension de la « mécanique » de Linq, je doute utiliser les requêtes, j’utiliserais ce qui est le plus près du code compilé (donc même les expressions lambdas ont de maigres  chances ..)
Par Romagny13
Ecrire un commentaire - Voir les commentaires - Recommander
Comparaison requête Linq et code compilé
I Requêtes ne renvoyant qu’un seul résultat :
Le type est automatiquement déduit (même avant compilation, il suffit de passer la souris sur le mot clé var pour s’en apercevoir)
            // SELECTION D'UN SEUL ELEMENT
            var Query =
                (from c in LstContacts
                 where c.ContactName.StartsWith("A")
                 select c).First<Contact>();
 
            Contact Query =        this.LstContacts.Where<Contact>(delegate(Contact c)
            {
                return c.ContactName.StartsWith("A");
            }).First<Contact>();
 
            // COUNT
            var Query =
                (from c in LstContacts
                 where c.ContactAge < 40
                 select c).Count<Contact>();
 
 
            int Query = this.LstContacts.Where<Contact>(delegate(Contact c)
            {
                return (c.ContactAge < 40);
            }).Count<Contact>();
 
I I  Requêtes renvoyant  une liste :
Les « clauses » se succèdent avec :
On distingue les « clauses »(SELECT,WHERE ,ORDERBY,etc.)qui  utilsent un delegate,, et les méthodes(exemple :First()) qui sont appelées directement
1 – SELECT seulement si pas de where
2 – WHERE puis ORDERBY (pas de WHERE !!)
3 – des l’instant que la clause ORDERBY est présente le résultat est stocké dans un IOrderedSequence, sinon il est stocké dans un IEnumerable
A – SELECT SIMPLE 
Le delegate ne fait que retourné un objet du type attendu (ici Contact)
            // SELECT simple (pas de where ni orderby)
            var Query =
               from c in LstContacts
               select c;
 
 IEnumerable<Contact> Query = this.LstContacts.Select<Contact, Contact>(delegate(Contact c)
            {
                return c;
            });
 
B– SELECT AVEC CLAUSE WHERE 
Le delegate effectue un filtre, seuls les objets correspondant à la condition (true) seront pris
            // AVEC UNE CLAUSE WHERE
            var Query =
               from c in LstContacts
               where c.ContactName.StartsWith("A")
               select c;
 
            IEnumerable<Contact> Query = this.LstContacts.Where<Contact>(delegate(Contact c)
            {
                return c.ContactName.StartsWith("A");
            });
 
C– SELECT AVEC ORDERBY 
Le delegate définie la propriété sur laquelle repose le trie
            // AVEC ORDER BY
            var Query =
              from c in LstContacts
              orderby c.ContactName
              select c;
 
            IOrderedSequence<Contact> Query = this.LstContacts.OrderBy<Contact, string>(delegate(Contact c)
            {
                return c.ContactName;
            });
            // ou
            this.dataGridView1.DataSource = this.LstContacts.OrderBy<Contact, string>(delegate(Contact c)
            {
                return c.ContactName;
            }).ToList<Contact>();
 
D– SELECT AVEC CLAUSE WHERE  ET ORDERBY
            //
            var Query =
                from c in LstContacts
                where c.ContactName.StartsWith("A")
                orderby c.ContactName
                select c;
 
            IOrderedSequence<Contact> Query = this.LstContacts.Where<Contact>(delegate(Contact c)
            {
                return c.ContactName.StartsWith("A");
            }).OrderBy<Contact, string>(delegate(Contact c)
            {
                return c.ContactName;
            });
 
E – AVEC PREDICATE
 
            // PREDICATE
            var Query = LstContacts.FindAll(FindContactsWhereContactNameStartsWith);
            //
            List<Contact> Query = this.LstContacts.FindAll(new Predicate<Contact>(this.FindContactsWhereContactNameStartsWith));
 
            //
            var Query =
               from c in LstContacts.FindAll(FindContactsWhereContactNameStartsWith)
               select c;
 
            IEnumerable<Contact> Query =
                this.LstContacts.FindAll(new Predicate<Contact>(this.FindContactsWhereContactNameStartsWith))
                .Select<Contact, Contact>(delegate(Contact c)
            {
                return c;
            });
 
public bool FindContactsWhereContactNameStartsWith(Contact c)
        {
            if (c.ContactName.StartsWith("A"))
                return true;
            else
                return false;
        }
 
F – AND ET OR (&& et ||)
C’est dans le délégué que les conditions sont traitées conjointement
            // AND
 
 var Query =
               from c in LstContacts
               where c.ContactName.StartsWith("A") && c.ContactName.StartsWith("B")
               select c;
 
 
            IEnumerable<Contact> Query = this.LstContacts.Where<Contact>(delegate(Contact c)
            {
                return c.ContactName.StartsWith("A") && c.ContactName.StartsWith("B");
            });
 
            // OR
            var Query2 =
              from c in LstContacts
              where c.ContactName.StartsWith("A") || c.ContactName.StartsWith("B")
              select c;
 
            IEnumerable<Contact> Query2 = this.LstContacts.Where<Contact>(delegate(Contact c)
            {
                return c.ContactName.StartsWith("A") || c.ContactName.StartsWith("B");
            });
 
Plusieurs champs de trie
            var Query =
              from c in LstContacts
              orderby c.ContactID, c.ContactName
              select c;
 
            IOrderedSequence<Contact> Query = this.LstContacts.OrderBy<Contact, int>(delegate(Contact c)
            {
                return c.ContactID;
            })
            .ThenBy<Contact, string>(delegate(Contact c)
            {
                return c.ContactName;
            });
 
G - Les Nullables
var Query =
              from c in LstContacts
              orderby c.ContactAge
              select c;
 
            IOrderedSequence<Contact> Query = this.LstContacts.OrderBy<Contact, int?>(delegate(Contact c)
            {
                return c.ContactAge;
            });
 
H - Création dynamique d’objets
-          Avec new (Query)
-          Avec initialisateurs d’objets (Query2)
   var Query =
              from c in LstContacts
              where c.ContactName.StartsWith("A")
              select new Contact(c.ContactID,c.ContactName,c.ContactAge,null);
 
 
            IEnumerable<Contact> Query = this.LstContacts.Where<Contact>(delegate(Contact c)
            {
                return c.ContactName.StartsWith("A");
            }).Select<Contact, Contact>(delegate(Contact c)
            {
                return new Contact(c.ContactID, c.ContactName, c.ContactAge, null);
            });
 
 
            var Query2 =
              from c in LstContacts
              where c.ContactName.StartsWith("A")
              select new Contact { ContactID = -1, ContactName = c.ContactName, ContactAge = c.ContactAge, ContactBirth = null };
 
 
            IEnumerable<Contact> Query2 = this.LstContacts.Where<Contact>(delegate(Contact c)
            {
                return c.ContactName.StartsWith("A");
            }).Select<Contact, Contact>(delegate(Contact c)
            {
                return new Contact { ContactID = -1, ContactName = c.ContactName, ContactAge = c.ContactAge, ContactBirth = null };
            });
 
I - Avec expression Lambda
 Contact oContact = LstContacts.First((Contact c) => c.ContactName.StartsWith("A"));
 
 
            Contact oContact = this.LstContacts.First<Contact>(delegate(Contact c)
            {
                return c.ContactName.StartsWith("A");
            });
 
 
 
J - Func
Func<Contact, bool> ContactFunction = c => c.ContactName.StartsWith("A");
            // les func sont en fait converties en méthodes anonymes(delegate)
            Func<Contact, bool> ContactFunction = delegate(Contact c)
            {
                return c.ContactName.StartsWith("A");
            };
 
         et comme la on commence à mieux comprendre comment fonctionne Linq on peut faire :
 
  Func<Contact, bool> ContactFunction = c => c.ContactName.StartsWith("A");
 
            var Query =
              from c in LstContacts
              where ContactFunction(c)
              select c;
 
Par Romagny13
Ecrire un commentaire - Voir les commentaires - Recommander
Namespace System.Linq
1 - L’interface IOrderedSequence >
C’est en fait un enumerable qui dispose d’un trie (icomparable)  + ordre (descending) sur une clé (key)
Hérite de IEnumerable (généric et non généric)
public interface IOrderedSequence<TElement> : IEnumerable<TElement>, IEnumerable
    {
        IOrderedSequence<TElement> CreateOrderedSequence<TKey>(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending);
    }
 
2 - Func
 
 public delegate TResult Func<TArg0, TResult>(TArg0 arg0);
 
3 - IComparer
public interface IComparer<T>
    {
        int Compare(T x, T y);
    }
 
4 - IQueryable generic et non generic
Hérite de IEnumerable + IQueryable
C’est donc une enumération (« collection ») sur laquelle peuvent s’appliquer des opérations(query)
public interface IQueryable<T> : IEnumerable<T>, IQueryable, IEnumerable
    {
        IQueryable<TElement> CreateQuery<TElement>(Expression expression);
        TResult Execute<TResult>(Expression expression);
    }
 
public interface IQueryable : IEnumerable
    {
        Type ElementType { get; }
        Expression Expression { get; }
 
        IQueryable CreateQuery(Expression expression);
        object Execute(Expression expression);
    }
 
5 - Expressions
Disposent quasiment toutes d’une method Buildstring
  expressions.jpg
Par Romagny13
Ecrire un commentaire - Voir les commentaires - Recommander
Etude personnelle - comparaison requêtes Linq et "avant"
 
Avant
           ContactCollection oSearchContacts = new ContactCollection();
 
            foreach (Contact oContact in oContacts)
            {
                if (oContact.City == "London")
                {
                    oSearchContacts.Add(oContact);
                }
            }
 
Avec Linq
 var result = from oContact in oContacts
                         where oContact.City == "London"
                         select oContact;
 
-          from > "dit en fait" pour chaque contact de la collection de contacts (c'est l'équivalent du foreach)
-          where est en fait l'equivalent du If (c'est à dire la condition)
-          select > on sélectionne le contact qui remplie les conditions (de la clause where)
-           result est une collection (enumerable) en fait correspond à oSearchContacts
Note : Orderby est très pratique et permet de trier facilement, « avant » on aurait utiliser IComparer et IComparable
dans le principe en fait rien de magique mais c'est dans l'architecture de Linq en lui-même que cela doit être complexe, et cet exemple est trés simple ...
de plus apparemment une "requete" Linq n'est exécutée que lorsque l'on fait une énumération, et c'est quand même une notion importante (ex : result.ToList())
Par Romagny13
Ecrire un commentaire - Voir les commentaires - Recommander
Introduction Linq
je considère l'accès aux objets métiers la partie de Linq presque la plus importante (bien que Linq To Xml et Linq To SQL le soient bien sur)
car en fait il me semble qu'il est mieux de passer par une couche métier plutot que d'attaquer directement une base de données ou un fichier Xml
 
une série d'articles sur C#3.0 devraient être postés car je commence l'exploration de ses nouveautés (toutes ne me semblent pas forcément bonnes, car par exemple on risque de ne plus savoir quelle solution employer pour l'accès aux données entre par exemple les datasets ,Linq to SQL ,Linq to DataSet...
 D’autres même si je ne les trouve pas forcément excellentes seront énormément employées telles le mot clé var ou les initialisateurs d'objets, les méthodes extensions sont en fait un peu un "gadget" je trouve)
Accès à des objets métiers
A - ContactCollection
using System;
using System.Text;
 
namespace TestOR
{
      public class ContactCollection:System.Collections.Generic.List<Contact>
      {
  
    }
}
 
 
B - Contact
using System;
using System.Text;
 
namespace TestOR
{
      public class Contact
      {
            private int m_ContactID;
            private string m_ContactName;
            private string m_ContactFirstName;
            private string m_ContactType;
 
            public Contact()
            {
            }
        public Contact(int ContactID, string ContactName, string ContactFirstName, string ContactType)
        {
            this.ContactID = ContactID;
            this.ContactName = ContactName;
            this.ContactFirstName = ContactFirstName;
            this.ContactType = ContactType;
        }
            public int ContactID
            {
                  get { return m_ContactID; }
                  set { m_ContactID = value; }
            }
            public string ContactName
            {
                  get { return m_ContactName; }
                  set { m_ContactName = value; }
            }
            public string ContactFirstName
            {
                  get { return m_ContactFirstName; }
                  set { m_ContactFirstName = value; }
            }
            public string ContactType
            {
                  get { return m_ContactType; }
                  set { m_ContactType = value; }
            }
      }
}
 
C - Test dans la form
            ContactCollection oContacts;
            oContacts = new ContactCollection();
 
            oContacts.Add(new Contact(1, "Durand", "Paul", "M"));
            oContacts.Add(new Contact(2, "Bellin", "Marie", "F"));
            oContacts.Add(new Contact(3, "Martin", "Pierre", "M"));
            oContacts.Add(new Contact(4, "Lemel", "Julie", "F"));
 
          
//ex 1 on selectionne tous les contacts qui sont des males(ContactType="M")
            //var oSearchContacts=from oContact in oContacts
            //                where oContact.ContactType=="M"
            //               select oContact;
 
//ex 2 ici on selectionne tous les contacts dont le nom commence par "B"
            var oSearchContacts = from oContact in oContacts
                                  where oContact.ContactName.StartsWith("B")
                                  select oContact;
           
            // Affichage
            foreach (Contact oContact in oSearchContacts)
            {
                listBox1.Items.Add(oContact.ContactName + " " + oContact.ContactFirstName);
            }

On dispose de nombreuses méthodes permettant de bien sélectionner les éléments recherchés

et c'est la tout l'interêt des "requêtes Linq" qui permettent vraiment de cibler facilement

  OrcasLinq.JPG

Par Romagny13
Ecrire un commentaire - Voir les commentaires - Recommander
Créer un blog sur over-blog.com - Contact - C.G.U. - Rémunération en droits d'auteur - Signaler un abus