web-dev-qa-db-fra.com

Appel de la méthode par défaut de l'interface C # à partir de la classe d'implémentation

C # 8 prend en charge les implémentations de méthodes par défaut dans les interfaces. Mon idée était d'injecter une méthode de journalisation dans des classes comme celle-ci:

public interface ILoggable {
    void Log(string message) => DoSomethingWith(message);
}

public class MyClass : ILoggable {
    void MyMethod() {
        Log("Using injected logging"); // COMPILER ERROR
    }
}

J'obtiens une erreur de compilation: "Le nom n'existe pas dans le contexte actuel"

Est-il impossible d'utiliser les implémentations de méthode par défaut de cette manière?

MODIFIER:

Pour la réponse correcte concernant les règles C #, voir réponse acceptée . Pour une solution plus concise (l'idée originale de ma question!) Voir ma propre réponse ci-dessous.

7
Andi

La réponse acceptée et les autres réponses sont correctes. Cependant, ce que je voulais, c'était un appel concis de la méthode Log. J'ai réalisé cela avec une méthode d'extension sur l'interface ILoggable:

public static class ILoggableUtils { // For extension methods on ILoggable
    public static void Log(this ILoggable instance, string message) {
         DoSomethingWith(message, instance.SomePropertyOfILoggable);
    }
}

De cette façon, je peux au moins appeler this.Log(...); dans ma classe au lieu du laid ((ILoggable)this).Log(...).

1
Andi

En lisant un article sur ces méthodes par défaut, je pense que vous devriez essayer de le transposer sur l'interface:

((ILoggable)this).Log("Using injected logging")

Je ne l'ai pas vérifié, juste ma pensée d'après this article

1
Vladimir

Si vous souhaitez éviter l'encombrement et la conversion répétitive, vous pouvez ajouter une seule propriété qui transforme le type en interface:

public class MyClass : ILoggable 
{
    ILoggable AsILoggable => (ILoggable)this;
    void MyMethod() 
    {
        AsILoggable.Log("Using injected logging"); 
    }
}

Mais c'est off. Cela semble faux, quelle que soit la façon dont cela se fait. De la documentation:

Le scénario le plus courant consiste à ajouter en toute sécurité des membres à une interface déjà publiée et utilisée par d'innombrables clients.

Quand il y avait une certaine inquiétude concernant les implémentations dans les interfaces - qui n'en avaient pas auparavant - c'était la phrase qui avait du sens. C'est un moyen d'ajouter à une interface sans casser les classes qui l'implémentent déjà.

Cette question implique que nous sommes modifiant la classe pour avoir une "conscience" de la nouvelle méthode. En d'autres termes, la contrainte implicite est que pour une raison quelconque, il est impossible de modifier la classe pour tenir compte de la nouvelle méthode d'interface. Modifier la classe pour dépendre de la nouvelle méthode indique exactement le contraire.

Si nous modifions déjà la classe, pourquoi ne pas simplement implémenter la méthode?

public void Log(string message) => DoSomethingWith(message);

Lorsque nous ajoutons une implémentation d'interface par défaut, nous fournissons une implémentation aux consommateurs de l'interface - des classes qui dépendent d'une abstraction.

Si nous dépendons de l'implémentation d'interface par défaut de within la classe qui implémente l'interface, alors une modification de l'interface devient, en fait, une modification de l'implémentation interne de la classe. Ce n'est pas à ça que sert une interface. Une interface représente un comportement externe, pas une implémentation interne.

C'est comme si la classe sortait d'elle-même, se regardait comme un consommateur externe et l'utilisait dans le cadre de son implémentation interne. La classe n'implémente pas l'interface, mais cela en dépend. C'est bizarre.

Je n'irai pas jusqu'à dire que c'est faux, mais cela se sent comme un abus de la fonctionnalité.

1
Scott Hannen