Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Tkfé

.Net passionnément, tout simplement

Actualités



  • Frédéric Mélantois
    A part boire du café ou du thé à longueur de journées, il m'arrive de coder ;-)
    Petite citation :
    Je n'éblouis pas mon entourage, je le fais rayonner. F.M. @1986
c# 3.0 : Surcharger une méthode d'extension (suite)

Après mon article Comprendre les bases de Linq to Objets et un post " c# 3.0 : Surcharger les méthodes d'extension ", je me suis décidé à écrire un mini-article sur les surcharges.

http://www.techheadbrothers.com/Astuces.aspx/surcharger-methode-extension 

Vous y découvrirez en particulier une astuce possible pour éviter d'effectuer un nouvel accès à la base de données via une requête Linq en couche de représentation sur une référence issue de la DAL pour laquelle on a employé Linq to SQL.

internal static class ExtensionLinq

{

    internal static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source,

   Func<TSource, TResult> selector)

    {

        IEnumerable<TSource> sourceEnum = source;

        foreach (TSource s in sourceEnum)

            yield return selector.Invoke(s);

    }

}

En C# 3.0, l'emploi des méthodes d'extension demandent de la discipline.
Il en est de même avec l'emploi du mot clé "var".

UPDATE DU POST
La ligne en rouge dans le code ne sert à rien. Voir les commentaires pertinents de Flavien Charlon ci-dessous. Bravo pour avoir vu cela ! Il nous reste à comprendre la logique du compilateur c# 3.0 avec Linq To SQL lorsque que j'effectue la surcharge de la méthode d'extension Select.

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :
Posted: dimanche 25 novembre 2007 20:48 par tkfe
Classé sous :

Commentaires

RaptorXP a dit :

Je ne comprends pas pourquoi on ne fait pas simplement :

   internal static IEnumerable

<TResult> Select<TSource, TResult="">(this IEnumerable<TSource> source, Func<TSource, TResult=""> selector)

   {

       foreach (TSource s in source)

           yield return selector.Invoke(s);

   }

a mon avis la ligne rouge est inutile, non ?

# novembre 26, 2007 12:21

tkfe a dit :

Comme expliqué dans l'article (peut-être mal expliqué), le résultat d'une requête Linq To SQL renvoie un objet implémentant IQueryable, et ceci a pour impact si on recaste la référence obtenu en IQueryable dans la couche de présentation, de refaire appel au mécanisme de Linq To SQL c'est à dire faire un nouvel appel à la base de données.

Pour éviter cela, la ligne rouge est importante.

Quelques liens de Mitsu (mis dans l'article) pour te permettre de mieux comprendre :

http://blogs.msdn.com/mitsufu/archive/2007/07/26/geek-quizz-ii-comment-stopper-l-imbrication-des-expressions-linq-to-sql.aspx

http://blogs.msdn.com/mitsufu/archive/2007/07/24/les-m-thodes-d-extension-de-c-3-r-ponse-au-quizz.aspx

Pour t'en convaincre, il te suffit de tester avec et sans la ligne rouge, en mettant des points d'arrêts sur les lignes de codes de ta couche de présentation.

# novembre 26, 2007 12:45

RaptorXP a dit :

Je suis d'accord, mais dans ta fonction Select, l'argument "source" est de type IEnumerable

<TSource>, tout comme "sourceEnum", donc la ligne rouge ne change rien. Dans les deux cas, c'est l'extension method de IEnumerable qui sera appellee.

Et avec ou sans cette ligne rouge, il est de toute façon impossible de re-caster le resultat en IQueryable puisque tu renvoie un resultat en utilisant yield return.

Tu as peut etre fait une faute de frappe et voulait mettre IQueryable<TSource> comme type pour l'argument "source".

# novembre 26, 2007 12:56

RaptorXP a dit :

Je corrige mon precedent commentaire: quel que soit le type de l'argument "source" (IQueryable ou IEnumerable), il n'y a pas besoin de le caster en IEnumerable pour lui appliquer un foreach (l'appel à GetEnumerator sera de toute façon le même).

Mais après reflexion, je suis quasiement sur que la ligne rouge ne sert à rien (c'est le foreach/yield return qui est important).

# novembre 26, 2007 14:14

tkfe a dit :

Flavien, tu as tout à fait raison sur le fait que la ligne rouge ne sert à rien !!!

Le pourquoi se tient dans le "yield return". J'aurai dû le savoir pour avoir regarder sous le capot de "yield return" et même d'en avoir parlé dans mon article "Comprendre les bases de Linq to Objects".

Le fait de réitérer crée un objet implémentant IEnumerable

<T> sous le capot.

Par contre, si on ne réalise pas la surcharge que je propose, comme la requête Linq to SQL renvoie une implémentation de IQueryable<T> (à savoir que IQueryable<T> implémente IEnumerable<T>, on se retrouve avec la possibilité de pouvoir rejouer avec Linq To SQL en castant en couche de présentation.

La grande question est pourquoi cette surcharge de la méthode Select de Linq To Objects, permet de modifier le comportement de notre couche d'accès. La réponse se trouve sans doute dans le compilateur c# 3 et le mécanisme de Linq To SQL.

# novembre 26, 2007 14:19

Matthieu MEZIL a dit :

Bien entendu, Flavien a raison. En effet, un IQueryable est un IEnumerable donc cette ligne "IEnumerable

<TSource> sourceEnum = source;" ne sert à rien.

En revanche, je ne comprend pas du tout ton histoire de cast.

On pourrait recaster dans la couche présentation si on retournait directement la source.

Dans la mesure où on reparcourt l'énumération et où on en recrait une avec yield return, il n'est plus possible de recaster en IQueryable. Donc on ne peut pas rejouer avec LINQ To SQL dans ce cas.

Où alors il y a quelque chose qui m'a échappé.

"La grande question est pourquoi cette surcharge de la méthode Select de Linq To Objects, permet de modifier le comportement de notre couche d'accès".

On est bien d'accord que l'extension method, ça n'existe pas au sens IL. Donc le compilateur doit appelait la méthode static. Pour cela, quand il peut choisir enytre plusieurs extension methods, il choisit celle la plus typée et, dans le cas où il y en aurait deux avec le même typage, il ne pourra pas choisir à moins qu'une et une seule des deux soient définies dans la même assembly et le même namespace.

Je ne vois pas où est le problème.

# novembre 27, 2007 14:20

Matthieu MEZIL a dit :

Petite correction à mon commentaire précédent :

Le compilateur choisit d'abord l'extension method la plus typée dans l'assembly et dans le namespace d'appel avant de chercher les autres dans le cas où il n'en trouve pas. C'est pour ça que même si ta redéfinition du Select prend un IEnumerable en paramètre et qu'il aurait pu trouver dans System.linq.Queryable.Select une extension method plus typé (avec un IQueryable), c'est la tienne qui est appelée.

# novembre 27, 2007 14:32

Matthieu MEZIL a dit :

J'apporte encore une dernière correction. On s'en fout que ce soit dans la même assembly.

Le compilateur cherche la méthode la plus typée dans le namespace et s'il n'en trouve pas, cherche dans le reste.

# novembre 27, 2007 14:42

tkfe a dit :

Pour plus de clarté voir le billet de Matthieu : http://blogs.developpeur.org/matthieu/archive/2007/11/27/extension-method-et-surcharge.aspx

Pour être complet, pourquoi la surcharge du Where ci-dessous ne fonctionne t-elle pas dans le cas de Linq to Sql ?

public static IEnumerable

<TSource> Where<TSource>(IEnumerable<TSource> source, Func<TSource, bool=""> selector)

   {

       return source;

   }

car il n'y a pas les mêmes paramètres de méthodes :

public static IQueryable<TSource> Where<TSource>(IQueryable<TSource> source, Expression<Func><TSource, bool="">&gt; expression)

tout simplement.

Pour être un peu plus complet, il existe un cas où la surcharge ne fonctionne pas!

si je requête :

(1)

var r = from h in MonContext.Personnes select h

ma surcharge fonctionne.

si je reqûete :

(2)

var r = from h in MonContext.Personnes where h.Personne_age &gt; 30 select h

ma surcharge ne fonctionne pas! C'est tout simplement parce que le compilateur fait l'économie d'un appel au Select dans le (2) car il est inutile de réitérer car la clause Where renvoie déjà un IQueryable.

Dans le cas (1), le Select est pratiqué afin de ne pas exposé Personnes qui est une Table<Personne> implémentant aussi l'interface IQueryable<Personne>.

Quizz :

si je reqûete :

(3)

var r = from h in MonContext.Personnes where h.Personne_age &gt; 30 select h.Personne_Nom

Ma surcharge fonctionne t-elle ?

Ps : vous devez répondre instantanément si vous avez

tout compris des explications de Flavien, de Matthieu et mes dernières.

# novembre 27, 2007 23:25

Mitsu a dit :

Allez, juste une petite critique, je trouve le mot surcharge mal adapté. La règle de choix d'une méthode d'extension se fait sur la nature de la référence puis sur la visibilité courante des définitions de méthodes d'extension. Même si on peut jouer sur cette visibilité, ce n'est pas une surcharge, c'est un remplacement. J'entends là que par exemple si tu remplaces le 'Select' de IQueryable par le tiens, il ne sera jamais utilisé par le provider qui implémente IQueryable...

C'est comme si on avait une donnée membre 'int i' dans une classe et qu'on déclarait une variable 'int i' dans une méthode. Elle aurait alors une portée plus courte et remplacerait la résolution de la donnée membre du même nom. Pour autant, on n'appelle pas ça une surcharge.

# décembre 16, 2007 13:43
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- [Refactoring] ReSharper pour Visual Studio 2010 (Preview) par Thomas Jaskula le il y a 12 heures et 16 minutes

- [Refactoring] Analyser vos exceptions avec ReSharper Exceptional par Thomas Jaskula le il y a 13 heures et 30 minutes

- SharePoint 2007 : patterns & practices SharePoint Guidance par Philippe Sentenac [MVP SharePoint] le 07-03-2009, 09:56

- [Visual Studio 2010] Les tests cases c’est bien, mais je vais devoir tout réécrire ? par Etienne Margraff le 07-03-2009, 09:00

- MVP[Gribouillon].AddYear par The Grib's Lair [Sébastien PICAMELOT - MVP SharePoint] le 07-03-2009, 08:45

- Clinique INSIA - Projet de fin d’Etudes (Silverlight 3 MVVM et OutOfBrowser, WCF, TFS) - Part 1 par David REI le 07-02-2009, 23:38

- C’est la crise ? Bah pourquoi cramer du budget pub alors ? par Nix's Blog le 07-02-2009, 15:31

- Soyons MVP ! par TheSaib .NET blog le 07-02-2009, 12:15

- SharePoint : Gestion des Erreurs 6398, 7076 et 6482 par Blog Technique de Romelard Fabrice le 07-02-2009, 11:53

- EF avec WPF par Matthieu MEZIL le 07-02-2009, 10:18