C# Language Bases de l'interface


Exemple

Une fonction d'interface appelée "contrat" ​​de fonctionnalité. Cela signifie qu'il déclare des propriétés et des méthodes mais ne les implémente pas.

Donc, contrairement aux classes Interfaces:

  • Ne peut être instancié
  • Ne peut avoir aucune fonctionnalité
  • Ne peut contenir que des méthodes * (les propriétés et les événements sont des méthodes internes)
  • L'héritage d'une interface s'appelle "Implementing"
  • Vous pouvez hériter d'une classe, mais vous pouvez "implémenter" plusieurs interfaces
public interface ICanDoThis{
    void TheThingICanDo();
    int SomeValueProperty { get; set; }
}

Choses à noter:

  • Le préfixe "I" est une convention de dénomination utilisée pour les interfaces.
  • Le corps de la fonction est remplacé par un point-virgule ";".
  • Les propriétés sont également autorisées car en interne elles sont aussi des méthodes
public class MyClass : ICanDoThis {
    public void TheThingICanDo(){
        // do the thing
    }

    public int SomeValueProperty { get; set; }
    public int SomeValueNotImplemtingAnything { get; set; }
}

.

ICanDoThis obj = new MyClass();

// ok
obj.TheThingICanDo();

// ok
obj.SomeValueProperty = 5;

// Error, this member doesn't exist in the interface
obj.SomeValueNotImplemtingAnything = 5;

// in order to access the property in the class you must "down cast" it
((MyClass)obj).SomeValueNotImplemtingAnything = 5; // ok

Ceci est particulièrement utile lorsque vous travaillez avec des frameworks d'interface utilisateur tels que WinForms ou WPF car il est obligatoire d'hériter d'une classe de base pour créer un contrôle utilisateur et vous perdez la possibilité de créer des abstractions sur différents types de contrôles. Un exemple? À venir

public class MyTextBlock : TextBlock {
    public void SetText(string str){
        this.Text = str;
    }
}

public class MyButton : Button {
    public void SetText(string str){
        this.Content = str;
    }
}

Le problème proposé est que les deux contiennent un concept de "texte" mais les noms de propriété diffèrent. Et vous ne pouvez pas créer une classe de base abstraite car ils ont un héritage obligatoire pour 2 classes différentes. Une interface peut atténuer cela

public interface ITextControl{
    void SetText(string str);
}

public class MyTextBlock : TextBlock, ITextControl {
    public void SetText(string str){
        this.Text = str;
    }
}

public class MyButton : Button, ITextControl {
    public void SetText(string str){
        this.Content = str;
    }

    public int Clicks { get; set; }
}

Maintenant, MyButton et MyTextBlock sont interchangeables.

var controls = new List<ITextControls>{
    new MyTextBlock(),
    new MyButton()
};

foreach(var ctrl in controls){
    ctrl.SetText("This text will be applied to both controls despite them being different");


    // Compiler Error, no such member in interface
    ctrl.Clicks = 0;

    // Runtime Error because 1 class is in fact not a button which makes this cast invalid
    ((MyButton)ctrl).Clicks = 0;


    /* the solution is to check the type first.
    This is usually considered bad practice since
    it's a symptom of poor abstraction */
    var button = ctrl as MyButton;
    if(button != null)
        button.Clicks = 0; // no errors

   
}