59 votes

Pourquoi est-il possible d'implémenter une méthode d'interface dans une classe de base ?

Dans mon projet, j'ai trouvé une situation étrange qui semble tout à fait valable en C#, car je n'ai aucune erreur de compilation.

Un exemple simplifié ressemble à cela :

using System;
using System.Collections.Generic;

namespace Test
{

    interface IFoo
    {
        void FooMethod();
    }

    class A
    {
        public void FooMethod()
        {
            Console.WriteLine("implementation");
        }
    }

    class B : A, IFoo
    {
    }

    class Program
    {
        static void Main(string[] args)
        {
            IFoo foo = new B();
            foo.FooMethod();
        }
    }
}

Un tel code se compile. Cependant, notez que A n'est pas IFoo y B ne met pas en œuvre IFoo méthodes. Dans mon cas, par accident (après le refactoring), A possède la méthode avec la même signature. Mais pourquoi A savoir comment mettre en œuvre le FooMethod de la IFoo l'interface ? A ne sait même pas que IFoo existent.

Pour moi, avoir un tel design est dangereux. En effet, chaque fois que j'implémente une interface, je dois vérifier si chaque méthode de cette interface "interfère" avec les méthodes de la classe de base.

Si c'est une "fonctionnalité purement C#" ? Comment s'appelle-t-elle ? Est-ce que quelque chose m'échappe ?

40voto

Marc Gravell Points 482669

Pour chaque membre de l'interface, le compilateur recherche simplement un fichier de type explicite (s'il y en a une), alors une public mise en œuvre ( implicite ), c'est-à-dire une méthode de l'API publique qui correspond à la signature de l'interface. Dans ce cas, A.FooMethod() semble être un bon choix pour une mise en œuvre publique. Si B n'était pas satisfait de cette sélection, il pouvait soit new la méthode, ou utiliser une implémentation explicite ; cette dernière solution serait préférable :

void IFoo.FooMethod() { /* explicit implementation */ }

20voto

LukeHennerley Points 3980

Le mot clé ici est implements . Votre classe de base, bien qu'elle ne connaisse rien au sujet de IFoo la signature de la méthode a été déclarée, qui implémente la méthode dans votre interface quelque part dans votre hiérarchie de classes.

Donc quand vous mettez en place IFoo dans la classe dérivée, la signature de la méthode est déjà implémentée dans la structure de la classe et il n'est donc pas nécessaire de l'implémenter à nouveau.

Si tu avais ça :

interface IFoo
{
  void FooMethod();
}
class A
{
  private void FooMethod(){}
}
class B : A, IFoo
{

}

Vous devez mettre en œuvre IFoo dans ce cas parce que le IFoo n'est pas accessible au moment où elle est mise en œuvre, et comme le dit Mark. Vous pouvez implémenter implicitement l'interface en faisant IFoo.FooMethod() pour s'assurer que vous avez une implémentation malgré le fait qu'une signature de méthode appropriée soit déjà définie dans la hiérarchie.

11voto

AakashM Points 32891

Vous dites dans un commentaire,

combien il est probable que celui qui a écrit la mise en œuvre de FooMethod en A qui n'implémente pas IFoo en fait, il s'agissait de mettre en œuvre IFoo ?

Eh bien, ça n'a pas d'importance ce que l'auteur de A pensée à l'époque de A La création de l'entreprise. C'est l'écrivain de B qui doit assumer la responsabilité du fait que B hérite à la fois de A ET met en œuvre IFoo . Il appartient à l'auteur de B de réfléchir aux conséquences de la définition de B .

Vous dites également

Dans mon cas, par accident (après le refactoring) A a la méthode avec la même signature

suggérant que cette situation est apparue après A y B avaient tous deux été écrits. Dans ce cas, la situation change : Lorsque l'on édite une classe qui est *héritée de * (telle que A ), il est de la responsabilité de l'éditeur de vérifier les effets de l'édition sur toutes les classes héritées. .

2voto

Matthew Watson Points 30804

Pour implémenter une interface, une classe doit seulement (a) déclarer qu'elle implémente cette interface (comme le fait votre classe B), et (b) fournir des implémentations pour toutes les méthodes définies dans l'interface, soit directement, soit indirectement via une classe de base (comme le fait votre classe B).

1voto

ebeeb Points 1584

Cette fonctionnalité s'appelle héritage . Et si vous n'aimez pas le design, ne l'utilisez pas. Beaucoup de gens n'aiment pas l'héritage, alors vous pourriez aussi le faire. La définition de l'héritage est que tous les membres de la classe de base sont également membres de la classe dérivée. Il n'y a donc pas d'erreur de compilation. Par conséquent, la classe dérivée met en œuvre le contrat IFoo fournit. C'est le membre de la classe de base qui répond à cette exigence.

La beauté de la chose, c'est que vous pouvez implémenter une interface par le biais d'un fichier de type fonctionnalité de base (virtuelle), qui peut être remplacée si un dérivé doit se comporter différemment.

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