Aller au contenu

Programmation C sharp/Interfaces

Un livre de Wikilivres.
Programmation C#
Programmation C#
Modifier ce modèle

Une interface ne fait que décrire une liste de méthodes, sans implémentation. Le code de ces méthodes est fourni par les classes qui implémentent l'interface.

Déclarer une interface

Le mot clé interface sert à déclarer une interface. Il est suivi par le nom de l'interface, qui par convention commence généralement par la lettre I (i majuscule comme interface).

Exemple :

public interface IAffichable
{
    /*
        Liste des méthodes que doivent posséder toutes les classes
        implémentant l'interface IAffichable :
    */
    void Afficher();
    void Afficher(string message);
}

Par convention, le nom d'une interface ne comportant qu'une seule méthode est celui de la méthode suivi du suffixe "able". Par exemple, si la seule méthode s'appelle Draw, l'interface est nommée IDrawable.

Utiliser une interface

L'interface créée est un nouveau type dont les méthodes sont appelables sans connaître la classe qui les implémente.

Exemple :

public void Montrer(IAffichable affichable,string message)
{
    affichable.Afficher(message);
}

Implémenter une interface

Une interface est implémentée par une classe la déclarant dans sa liste d'implémentation. Cette classe doit alors fournir le code de toutes les méthodes de l'interface, à moins de déclarer ces méthodes comme abstraites. Dans ce dernier cas, l'implémentation devra être effectuée par une sous-classe.

Exemple :

using System;

public class Personne : IAffichable
{
    private string nom, prenom;

    public Personne(string nom, string prenom)
    {
        this.nom = nom;
        this.prenom = prenom;
    }

    public void Afficher()
    {
        Console.WriteLine(nom+" "+prenom);
    }

    public void Afficher(string message)
    {
        Console.WriteLine(nom+" "+prenom+" : "+message);
    }
}

Une interface peut être implémentée de manière implicite ou explicite.

Implémentation implicite

L'implémentation implicite est illustrée par l'exemple précédent. L'appel aux méthodes de l'interface peut se faire en utilisant une référence à un objet Personne ou à une interface IAffichable :

Personne p = new Personne(nom, prenom);
p.Afficher();  // Appel via un objet Personne

IAffichable a = (p as IAffichable);
a.Afficher();  // Appel via une référence à l'interface

Implémentation explicite

L'implémentation explicite se fait en donnant explicitement le nom de l'interface correspondant à la méthode implémentée.

L'interface IClonable déclare une méthode retournant un objet identique à l'objet utilisé :

public interface ICloneable
{
    object Clone();
}

L'implémentation explicite pour la classe Personne est la suivante :

using System;

public class Personne : IClonable
{
    private string nom, prenom;

    public Personne(string nom, string prenom)
    {
        this.nom = nom;
        this.prenom = prenom;
    }

    object ICloneable.Clone()
    {
        return new Personne(nom, prenom);
    }
}

La méthode ne déclare pas sa visibilité car c'est la même que celle de l'interface.

L'utilisation de la méthode ne peut alors se faire que par une référence à l'interface :

Personne p = new Personne(nom, prenom);
object p2 = (p as ICloneable).Clone();  // Appel via une référence à l'interface

Il n'est pas possible de l'appeler directement avec une référence à l'objet :

Avertissement Ce code contient une erreur volontaire !
object p3 = p.Clone();  // Erreur

La méthode n'est alors pas considérée comme une méthode de l'objet mais de l'interface. Il est donc possible d'en définir une autre (surcharge) avec une différence sur le type de retour seulement :

using System;

public class Personne : IClonable
{
    private string nom, prenom;

    public Personne(string nom, string prenom)
    {
        this.nom = nom;
        this.prenom = prenom;
    }

    object ICloneable.Clone()  // 1
    {
        return new Personne(nom, prenom);
    }

    Personne Clone()  // 2
    {
        return new Personne(nom, prenom);
    }
}

L'appel via l'objet ou l'interface définit quelle méthode est appelée :

Personne p = new Personne(nom, prenom);
object p2 = (p as ICloneable).Clone(); // Appel à Clone 1 retournant object
Personne p3 = p.Clone();               // Appel à Clone 2 retournant Personne

Dans le cas où une classe implémente plusieurs interfaces ayant une ou des méthodes communes (même nom et types des arguments) mais dont la sémantique diffère, l'implémentation explicite permet de fournir une implémentation différente pour chaque interface.

Méthodes, propriétés, indexeurs, events

Une interface peut en fait déclarer des méthodes, des propriétés, des indexeurs et des events.

Note : Lorsque vous utilisez un accesseur pour implémenter une interface, l'accesseur peut ne pas avoir de modificateur d'accès. [...] [[1] MSDN]

Exemple :

public interface IExemple
{
    // Méthode à implémenter :
    void UneMethodeAImplementer();

    // Propriétés à implémenter :
    string UneProprieteAImplementer { get; set; }
    string UneProprieteLectureSeuleAImplementer { get; }

    // Tableau de string à implémenter (indexeur) :
    string this [ int index ] { get; set; }

    // Evènement à implémenter :
    event PageRecueDelegate PageRecue;
}

L'implémentation des propriétés peut se faire de manière explicite, détaillée dans la section précédente.

Une implémentation explicite d'un évènement oblige à fournir une implémentation des méthodes add et remove.

Héritage

Une interface peut hériter d'une autre interface. Elle possède donc les mêmes déclarations que l'interface de base en plus de ces propres déclarations. En outre, elle peut être utilisée là ou une implémentation de l'interface de base est requise.

Exemple :

public interface IDrawable
{
    void Draw();
}

public interface IPrintable : IDrawable
{
    void Print();
}

public class Cercle : IPrintable
{
    public void Draw()
    {
        ...
    }

    public void Print()
    {
        ...
    }
}

...
public void Methode()
{
    IDrawable drawable = new Cercle();
    // ^ conversion implicite de IPrintable vers IDrawable
    drawable.Draw();
}