Реализация по умолчанию метода для интерфейсов С#?

Можно ли определить интерфейс на С#, который имеет реализацию по умолчанию? (так что мы можем определить класс, реализующий этот интерфейс без реализации этого конкретного метода по умолчанию).

Я знаю методы расширения (как описано в этой ссылке). Но это не мой ответ, потому что, имея расширение метода, подобное следующему, компилятор все еще жалуется на реализацию MyMethod в 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
}

Я спрашиваю об этом, потому что (по крайней мере, насколько я понимаю) это можно сделать на Java (см. здесь).

PS: с абстрактным базовым классом с некоторым методом также является not мой ответ просто потому, что у нас нет множественного наследования в С#, и он отличается от того, по умолчанию для интерфейсов (если возможно!).

Ответ 1

Я разрабатываю игры, поэтому часто хочу иметь общую функцию для всех реализаций интерфейса, но в то же время позволяет каждой реализации делать свою собственную вещь, так же, как и функции виртуального/переопределения подкласса.

Вот как я это делаю:

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 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 Move function
        // And then it will proceed to executing Robocop 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) { }
}

Ответ 2

Краткий ответ:

Нет, вы не можете написать реализацию метода в интерфейсах.

Описание:

Интерфейсы подобны контракту, так что типы, которые будут наследовать от него, должны будут определить реализацию, если у вас есть сценарий, вам нужен метод с реализацией по умолчанию, тогда вы можете сделать свой класс abstract и определить реализацию по умолчанию для метода, который вы хотите.

Пример:

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

    public abstract string SomeMethodWhichDerivedTypeWillImplement();
}

и теперь в классе Dervied:

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

Ответ 3

С# v8 начнет допускать реализацию конкретного метода в интерфейсах. Это позволит вашим конкретным классам реализации не прерываться при изменении интерфейсов, которые будут реализованы в будущем.

В следующей версии языка может быть что-то подобное:

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

Обратитесь к этой проблеме GitHub № 288. Кроме того, Mads Torgersen подробно рассказывает об этой предстоящей функции в этом канале 9 видео.

Примечание. Текущая версия языка С# в состоянии RTM равна v7 во время написания этого ответа.

Ответ 4

Не напрямую, но вы можете определить метод расширения для интерфейса, а затем реализовать его как-то вроде этого

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();
    }
}

Изменить * Важно, чтобы метод расширения и метод, который вы выполняете, называются по-разному, иначе вы, скорее всего, получите stackoverflow.