web-dev-qa-db-fra.com

Implémentation par défaut d'une méthode pour les interfaces C #?

Est-il possible de définir une interface en C # ayant une implémentation par défaut? (afin que nous puissions définir une classe implémentant cette interface sans implémenter cette méthode particulière par défaut).

Je connais méthodes d'extension (comme expliqué dans ce lien par exemple). Mais c’est pas ma réponse car ayant une extension de méthode comme celle-ci, le compilateur se plaint toujours de l’implémentation de MyMethod dans MyClass:

public interface IMyInterface
{
    string MyMethod();
}

public static class IMyInterfaceExtens
{
    public static string MyMethod(this IMyInterface someObj)
    {
        return "Default method!";
    }
}

public class MyClass: IMyInterface
{
// I want to have a default implementation of "MyMethod" 
// so that I can skip implementing it here
}

Je demande cela parce que (du moins si je comprends bien), il est possible de le faire en Java (voir ici ).

PS: avoir une classe de base abstraite avec une méthode est aussi pas ma réponse simplement parce que nous n'avons pas d'héritage multiple en C # et que cela diffère de la mise en œuvre par défaut des interfaces (si possible!) .

22
Akhir

Je développe des jeux et je souhaite souvent avoir une fonction commune pour toutes les implémentations d’une interface, tout en permettant à chaque implémentation de faire sa propre chose, un peu comme les méthodes de substitution virtuelle d’une sous-classe fonctionneraient.

Voici comment je le fais:

public class Example
{
    void Start()
    {
        WallE wallE = new WallE();
        Robocop robocop = new Robocop();

        // Calling Move() (from IRobotHelper)
        // First it will execute the shared functionality, as specified in IRobotHelper
        // Then it will execute any implementation-specific functionality,
        // depending on which class called it. In this case, WallE's OnMove().
        wallE.Move(1);

        // Now if we call the same Move function on a different implementation of IRobot
        // It will again begin by executing the shared functionality, as specified in IRobotHlper's Move function
        // And then it will proceed to executing Robocop's OnMove(), for Robocop-specific functionality.
        robocop.Move(1);

        // The whole concept is similar to inheritence, but for interfaces.
        // This structure offers an - admittedly dirty - way of having some of the benefits of a multiple inheritence scheme in C#, using interfaces.
    }

}

public interface IRobot
{
    // Fields
    float speed { get; }
    float position { get; set; }

    // Implementation specific functions.
    // Similar to an override function.
    void OnMove(float direction);
}

public static class IRobotHelper
{
    // Common code for all IRobot implementations. 
    // Similar to the body of a virtual function, only it always gets called.
    public static void Move(this IRobot iRobot, float direction)
    {
        // All robots move based on their speed.
        iRobot.position += iRobot.speed * direction;

        // Call the ImplementationSpecific function
        iRobot.OnMove(direction);
    }
}

// Pro-Guns robot.
public class Robocop : IRobot
{
    public float position { get; set; }

    public float speed { get; set;}

    private void Shoot(float direction) { }

    // Robocop also shoots when he moves
    public void OnMove(float direction)
    {
        Shoot(direction);
    }
}

// Hippie robot.
public class WallE : IRobot
{
    public float position { get; set; }

    public float speed { get; set; }

    // Wall-E is happy just moving around
    public void OnMove(float direction) { }
}
25

C # v8 commencera à permettre l'implémentation de méthodes concrètes dans les interfaces. Cela permettra à vos classes d'implémentation concrètes de ne pas être interrompues lorsque vous modifierez les interfaces implémentées à l'avenir.

Donc, quelque chose comme cela sera possible dans la prochaine version linguistique:

interface IA
{
    void NotImplementedMethod();
    void M() { WriteLine("IA.M"); } //method definition present in the interface
}

Veuillez vous référer à ce GitHub numéro # 288 . Mads Torgersen parle également de cette fonctionnalité à venir dans la vidéo this channel 9.

Note: la version actuelle du langage C # à l'état RTM est la v7 au moment de la rédaction de cette réponse.

18
RBT

Réponse courte:

Non, vous ne pouvez pas écrire l'implémentation de la méthode dans les interfaces.

La description:

Les interfaces sont comme un contrat, de sorte que les types qui en hériteront devront définir l’implémentation. Si vous avez un scénario, vous avez besoin d’une méthode avec une implémentation par défaut, vous pouvez créer votre classe abstract and Définissez l'implémentation par défaut de la méthode souhaitée.

Par exemple:

public abstract class MyType
{
    public string MyMethod()
    {
      // some implementation
    }

    public abstract string SomeMethodWhichDerivedTypeWillImplement();
}

et maintenant en classe Dervied:

public class DerivedType : MyType
{
  // now use the default implemented method here
}

UPDATE (C # 8 sera supporté pour cela):

C # 8 permettra d'avoir une implémentation par défaut dans les interfaces

15
Ehsan Sajjad

Pas directement, mais vous pouvez définir une méthode d'extension pour une interface, puis l'implémenter comme ceci

public interface ITestUser
{
    int id { get; set; }
    string firstName { get; set; }
    string lastName { get; set; }

    string FormattedName();
}

static class ITestUserHelpers
{
    public static string FormattedNameDefault(this ITestUser user)
    {
        return user.lastName + ", " + user.firstName;
    }
}

public class TestUser : ITestUser
{
    public int id { get; set; }
    public string firstName { get; set; }
    public string lastName { get; set; }

    public string FormattedName()
    {
        return this.FormattedNameDefault();
    }
}

Edit * Il est important que la méthode d’extension et celle que vous implémentez soient nommées différemment, sinon vous obtiendrez probablement un stackoverflow.

5
Tim M

En tant que nouveau programmeur C #, je lisais ce sujet et je me demandais si l'exemple de code suivant pouvait être utile (je ne sais même pas si c'est la bonne façon de le faire). Pour moi, cela me permet de coder le comportement par défaut derrière une interface. Notez que j'ai utilisé la spécifiction de type générique pour définir une classe (abstraite).

namespace InterfaceExample
{
    public interface IDef
    {
        void FDef();
    }

    public interface IImp
    {
        void FImp();
    }

    public class AbstractImplementation<T> where T : IImp
    {
        // This class implements default behavior for interface IDef
        public void FAbs(IImp implementation)
        {
            implementation.FImp();
        }
    }

    public class MyImplementation : AbstractImplementation<MyImplementation>, IImp, IDef
    {
        public void FDef()
        {
            FAbs(this);
        }
        public void FImp()
        {
            // Called by AbstractImplementation
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyImplementation MyInstance = new MyImplementation();

           MyInstance.FDef();
        }
    }
}
0
Jurgen Wilsch