Délégation d’implémentation d’interface: réponse au Quizz


Tout d'abord, toute mon estime à Tétranos pour sa réponse à la question bonus.


En effet, je tentais de résoudre la délégation d'implémentation d'interface...mais qu'est-ce donc ?


En C#, si vous voulez implémenter une interface dans une classe quelconque, vous êtes bons pour implémenter tout ce qu'elle définit.


Parfois, la classe en question aggrège une instance interne qui implémente cette interface et il est alors fort tentant de déléguer l'implémentation de notre interface à cet objet.


Hors en C#, aucune syntaxe n'existe pour cela.


Le framework nous montre à plusieurs endroits qu'il est possible de mettre facilement en place un pattern qui simule ce comportement.


Prenons l'interface IList. Elle hérite de ICollection, qui hérite de IEnumerable. Si vous voulez implémenter IList vous vous retrouvez avec environ une vingtaine de méthodes à implémenter.
Assez laborieux et on aimerait dans de nombreux cas déléguer ça à une classe commune générique et paramétrable plutôt que de tout réimplémenter à chaque fois.


Pour cette interface précise, le framework .Net apporte une autre interface qui est IListSource. Cette interface définit tout simplement une méthode "IList GetList()". Dans cette méthode, nous pouvons renvoyer n'importe quelle implémentation de IList.


Attention ce n'est pas suffisant. En effet, implémenter IListSource ne vous fait pas implémenter IList. Cependant, le pattern définit que lorsque les codes appelants IList (comme dans le databinding des winforms ou de WPF), ne trouvent pas IList implémenté dans leur cible, alors ils doivent tester IListSource.


C'est en effet grâce à ce travail "d'équipe" que nous arrivons à substituer la délégation d'implémentation d'interface dans le framework .Net.


Un autre très bon exemple: IEnumerable face à IEnumerator.


A bientôt pour un prochain Quizz,


Mitsu

Comments (11)

  1. Tetranos says:

    Waouh…je vais montrer ce post à mon manager 🙂

  2. Donc, si j’ai bien compris, on remplace l’utilisation d’une classe abstraitre implémentant l’interface (en amont de la classe qui nous intéresse) par une délégation au coeur même de la classe implémentant elle-même directement l’interface.

    J’ai juste ?

  3. Tetranos says:

    Pour faire simple :

    – C1 doit implémenter I

    – C1 agrége de C2

    – C2 implémente I

    Delphi permet de dire que C1 implémente I au travers de C2.

    i.e.

    L’implémentation de I par C1 est déléguée à C2

  4. GeoVah says:

    Impeccable pour l’interface IList, mais comment faire pour IMonInteraceAMoi ?

  5. Simon says:

    J’avoue, j’étais loin ^^.

    Pour GeoVah, il faut prendre le même principe, passer par une 2e interface permettant de récupérer une instance de la première.

  6. GeoVah says:

    @Simon :

    Si on regarde ce que voulais faire Mitsuru dans son article précédent (http://blogs.msdn.com/mitsufu/archive/2007/07/27/quizz-iii-subtilit-s-dans-les-conversions.aspx), Le but était de l’implémenter de manière automatique ..

    Mais comme il est écrit :

    "Cependant, le pattern définit que lorsque les codes appelants IList (comme dans le databinding des winforms ou de WPF), ne trouvent pas IList implémenté dans leur cible, alors ils doivent tester IListSource."

    Si on veut pouvoir le faire, c’est uniquement ciblé en utilisant un pattern bien précis pour tout les consommateurs de l’interface

  7. Simon says:

    Exactement, les composants consommant IMonInterfaceAMoi, doivent aussi être capable de travailler avec IMonInterfaceAMoiSource

  8. Mitsu Furuta says:

    Sans arriver à qque chose de 100% automatique, on peut imaginer généraliser ce pattern:

    using System;

    using System.Collections.Generic;

    using System.Text;

    namespace TestInterfaceDelegation

    {

       class Program

       {

           static void Main(string[] args)

           {

               var t = new Test();

               IMyInterface mi = t.As<IMyInterface>();

               IDisposable id = t.As<IDisposable>();

               // Si Test n’implémentait que ISource<IMyInterface>,

               // l’inférence accepterait: t.As()

               // ce qui n’est pas top à lire.

               // Mieux vaut s’appliquer à écrire: t.As<IMyInterface>();

           }

       }

       //Pattern générique:

       public interface ISource<T>

       {

           T GetInterface();

       }

       public static class SourceExtensions

       {

           public static T As<T>(this ISource<T> source) where T : class

           {

               return source.GetInterface();

           }

       }

       //Exemple:

       public interface IMyInterface

       {

       }

       public class MyInterfaceImplementation : IMyInterface

       {

       }

       public class Test : ISource<IMyInterface>, ISource<IDisposable>

       {

           MyInterfaceImplementation mii = new MyInterfaceImplementation();

           #region ISource<IMyInterface> Members

           public IMyInterface GetInterface()

           {

               return mii;

           }

           #endregion

           #region ISource<IDisposable> Members

           IDisposable ISource<IDisposable>.GetInterface()

           {

               throw new NotImplementedException();

           }

           #endregion

       }

    }

    Mitsu

  9. Soit la méthode de ma couche business suivante: IQueryable &lt; Customer &gt; GetCustomers() { return

  10. mathmax says:

    Pourquoi C# n’implémente t-il pas la délégation d’implémentation d’interface ? Y a t-il des inconvénients dans sa pratique ? Peut-on s’attendre à ce que cala soit supporté dans une future version du language ?

  11. Olivier says:

    Je tombe sur ce post qui date de quelques mois car justement j’essaye de trouver un moyen de déléguer l’implémentation de certaines interfaces à des objets imbriqués dans d’autres.

    Je reste malgré tout sur ma faim.

    Pour ingénieuse qu’elle soit, l’astuce proposée n’est pas satisfaisante car elle ne règle le problème que "philosophiquement" pas pratiquement.

    En ajoutant du code et des contraintes de dev on peut régler tous les problèmes avec tous les langages, ce n’est bien sûr pas ce qu’on attend d’un langage moderne.

    Il est dommage que Anders ait oublié cette feature qu’il avait mise dans Delphi.

    C’est un peu (très même) frustrant ce manque de délégation des interfaces.

    Mais je garde mon baril de C#, je ne l’échange pas contre deux même dix barils de xxxxx (censuré pour ne blesser personne).

    Mitsu, si tu vois des gars de l’équipe C# aux States, pense à le faire ajouter sur la wish list pour C# 4 !

Skip to main content