62 votes

Délégués et interfaces en C#

Je voudrais poser cette question dans la mesure où j'essaie actuellement de creuser l'utilisation et le but des délégués, bien qu'il soit probable qu'elle ait été posée dans des formulations similaires.

Je sais que les délégués servent de pointeurs de fonction utilisés en C++. Le fait est qu'en C#, ils servent surtout d'alternative aux interfaces et au polymorphisme. Puisque je peux créer des sous-classes d'une classe spécifique et leur fournir les méthodes appropriées à chacune, qu'est-ce que les délégués offrent de plus ? Y a-t-il des cas qui stipulent leur utilisation ou est-ce que la maintenabilité du code est simplement améliorée lorsque les délégués sont utilisés ? Recommanderiez-vous leur déploiement à grande échelle par rapport aux interfaces ?

Je parle uniquement des délégués et je veux distinguer leur rôle de celui des événements.

5 votes

"Le fait est que si en C# ils servent surtout d'alternative aux interfaces et au polymorphisme" - veuillez expliquer votre raisonnement.

6 votes

Ce n'est qu'une question (indirecte). Je perçois leur fonctionnalité comme décrite dans ma question et je veux savoir si vous êtes d'accord et si c'est vrai.

80voto

Jon Skeet Points 692016

Oui, les délégués sont à bien des égards comme des interfaces à méthode unique. Cependant :

  • Il y a un support intégré dans le CLR pour eux.
  • Le cadre de travail les prend en charge, notamment les capacités de multidiffusion et les invocations asynchrones.
  • Il existe une prise en charge supplémentaire du langage C#/VB sous la forme de conversions de groupes de méthodes, d'expressions lambda et de méthodes anonymes.
  • Ils sont mandatés pour les événements (c'est-à-dire que les événements et les délégués sont une sorte de paire assortie).
  • Ils veulent dire que vous Ne le fais pas. vous devez implémenter une interface dans une classe distincte pour chaque instance de délégué que vous souhaitez créer.

Le dernier point est le plus important : considérez une expression LINQ de :

var query = collection.Where(x => x > 5)
                      .Select(x => x * x);

Imaginez maintenant que pour exprimer la logique de x > 5 et x * x vous deviez écrire une classe distincte pour chaque expression, et implémenter une interface : la quantité de code inutile par rapport au code utile serait ridicule. Maintenant, bien sûr, le langage podría ont été conçus pour permettre les conversions d'expressions lambda en implémentations d'interfaces via des classes séparées, mais vous perdriez alors l'avantage de pouvoir simplement écrire une méthode séparée et créer un délégué avec cette méthode comme cible. Vous perdriez également les capacités de multi-cast.

À titre d'exercice de réflexion similaire, envisagez des instructions en boucle telles que while et for . Est-ce que nous besoin de quand nous avons goto ? Non. Mais la vie est bien meilleure avec les. Il en va de même pour les délégués - et même pour les propriétés, les événements, etc. Ils rendent tous le développement plus simple.

5 votes

Je ne considérerais pas l'exemple Linq comme montrant un avantage des délégués ; même si le type de délégué Func<int, bool> ont été remplacés par l'interface IFunc<int, bool> Si l'interface n'est pas implémentée, un compilateur pourrait facilement définir une classe qui implémente cette interface et inclut une propriété statique publique qui renvoie une instance statique privée. Une telle approche fonctionnerait à peu près de la même manière que les délégués pour les expressions lambda qui ne se ferment pas sur des locaux, et serait plus efficace que les délégués pour les expressions lambda qui se ferment sur des locaux.

0 votes

@supercat : L'exemple de LINQ montre comment avoir du sucre syntaxique pour cela est grandement bénéfique. Il podría avec des interfaces, bien sûr, mais ce n'est pas le cas en C#, et ce n'est pas le cas en France. mais en Java. Notez que pour une expression lambda qui se ferme sur des variables locales, vous ne pourriez pas avoir une seule instance de toute façon, car vous auriez besoin de créer une nouvelle instance à chaque fois pour contenir la variable capturée.

4 votes

Je pense que j'ai mal interprété la question initiale, la considérant comme plus théorique que pratique ; si le framework .net avait été conçu autour d'interfaces plutôt que de délégués, les compilateurs fourniraient presque certainement les mêmes types de support pour les premières que pour les seconds. En ce qui concerne les fermetures, la création d'une fermeture nécessite actuellement la création d'un objet pour contenir les variables et d'un délégué qui contient une référence à cet objet et à la fonction souhaitée ; si l'on pouvait utiliser des interfaces au lieu des délégués, le compilateur pourrait simplement créer un objet qui remplirait les deux fonctions.

35voto

dasblinkenlight Points 264350

Le plus grand pratique La différence est que vous pouvez fournir différentes instances de délégué pour le même délégué de la même classe, alors que vous ne pouvez pas le faire avec les interfaces.

delegate void XYZ(int p);

interface IXyz {
    void doit(int p);
}

class One {
    // All four methods below can be used to implement the XYZ delegate
    void XYZ1(int p) {...}
    void XYZ2(int p) {...}
    void XYZ3(int p) {...}
    void XYZ4(int p) {...}
}

class Two : IXyz {
    public void doit(int p) {
        // Only this method could be used to call an implementation through an interface
    }
}

20voto

Lion Points 7328

Desde Quand utiliser des délégués au lieu d'interfaces (MSDN) :

Les délégués et les interfaces permettent au concepteur d'une classe de séparer les déclarations de type et l'implémentation. Une interface donnée peut être héritée et implémentée par n'importe quelle classe ou structure. Un délégué peut être créé pour une méthode de n'importe quelle classe, à condition que la méthode corresponde à la signature de la méthode pour le délégué. Une référence à une interface ou un délégué peut être utilisé par un objet qui ne connaît pas la classe qui implémente l'interface ou la méthode du délégué. Compte tenu de ces similitudes, quand le concepteur d'une classe doit-il utiliser un délégué et quand doit-il utiliser une interface ?

Utilisez un délégué dans les circonstances suivantes :

  • Un modèle de conception événementiel est utilisé.
  • Il est souhaitable d'encapsuler une méthode statique.
  • L'appelant n'a pas besoin d'accéder aux autres propriétés, méthodes ou interfaces de l'objet qui implémente la méthode.
  • Une composition facile est souhaitée.
  • Une classe peut avoir besoin de plus d'une implémentation de la méthode.

Utilisez une interface dans les circonstances suivantes :

  • Il existe un groupe de méthodes connexes qui peuvent être appelées.
  • Une classe n'a besoin que d'une seule implémentation de la méthode.
  • La classe qui utilise l'interface voudra convertir cette interface en d'autres types d'interfaces ou de classes.
  • La méthode mise en œuvre est liée au type ou à l'identité de la classe : par exemple, les méthodes de comparaison.

Un bon exemple d'utilisation d'une interface à méthode unique au lieu d'un délégué est le suivant IComparable ou la version générique, IComparable (De T). IComparable déclare la méthode CompareTo, qui renvoie un nombre entier spécifiant une relation inférieure, égale ou supérieure à deux objets du même type. IComparable peut être utilisé comme base d'un algorithme de tri. Bien que l'utilisation d'une méthode de comparaison de délégués comme base d'un algorithme de tri soit valable, elle n'est pas idéale. Comme la capacité de comparaison appartient à la classe et que l'algorithme de comparaison ne change pas au moment de l'exécution, une interface à méthode unique est idéale.

Desde Délégués et interfaces en C# :

Les délégués et les interfaces sont deux concepts distincts en C#, mais ils ont un point commun. Les délégués et les interfaces ne comprennent que la déclaration. L'implémentation est effectuée par un objet de programmation différent.

2 votes

Réponse utile ; si vous ou quelqu'un d'autre pouvait ajouter des exemples de vos points 2-5 où un délégué peut être utile, ce serait bien aussi. Le modèle de l'événementiel n'a pas besoin d'être illustré par des exemples puisqu'il est largement discuté.

4voto

aleroot Points 30853

Les délégués et les interfaces sont deux concepts distincts en C#.

Les interfaces permettent d'étendre la fonctionnalité d'un objet, c'est un contrat entre l'interface et l'objet qui l'implémente, alors que les délégués sont juste des rappels sûrs, ce sont des sortes de pointeurs de fonction.

2voto

supercat Points 25534

Les seuls avantages réels des délégués par rapport aux interfaces sont

  1. Les délégués pouvaient traiter des types d'arguments différents avant même que .Net ne prenne en charge les génériques.
  2. Une classe peut créer des délégués exposant plusieurs méthodes différentes partageant la même signature ; le remplacement des délégués par des interfaces signifierait que chaque classe pourrait exposer une méthode implémentant chaque interface de style délégué sans créer de classes d'aide, mais aurait besoin d'une classe d'aide pour chaque implémentation supplémentaire.

Lorsque .net ne supportait pas les génériques, les délégués en étaient une partie essentielle puisque déclarer des interfaces non génériques distinctes pour chaque signature de fonction différente que l'on voulait passer aurait été irréalisable. Si .net avait supporté les génériques dès le début, les délégués n'auraient pas été nécessaires, sauf pour certains scénarios impliquant Reflection, et même là, il aurait peut-être été plus utile d'avoir le type Action<T,U> être une mise en œuvre de IAction<T,U> (de sorte que le code qui a simplement besoin de quelque chose qu'il peut Invoke utiliserait l'interface). Une approche basée sur l'interface aurait nécessité la création de classes à méthode unique dans les cas où les classes doivent créer des délégués exposant plusieurs méthodes, mais aurait éliminé la nécessité de créer des instances de délégués distinctes dans les nombreux cas courants où le nombre de méthodes d'une signature donnée à exposer est précisément un.

Au demeurant, le remplacement des délégués par des interfaces n'empêcherait nullement la création d'une méthode Combine à usage général. En effet, la covariance des interfaces pourrait permettre à une telle méthode de fonctionner mieux que l'actuelle méthode Delegate.Combine à bien des égards. La mise en œuvre d'une méthode analogue à Delegate.Remove serait au mieux maladroit et ennuyeux, mais je ne vois pas d'autre situation que la gestion des abonnements aux événements qui nécessiterait l'utilisation de l'option Delegate.Remove et l'abonnement aux événements pourrait de toute façon être mieux géré en utilisant d'autres approches.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X