Default implementation of a method for C# interfaces?
Asked Answered
L

7

65

Is it possible to define an interface in C# which has a default implementation? (so that we can define a class implementing that interface without implementing that particular default method).

I know extension methods (as explained in this link for example). But that is not my answer because having a method extension like the following, the compiler still complains about implementing MyMethod in 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
}

I am asking this because (at least as far as I understand) it is possible to do so in Java (see here).

PS: having an abstract base class with some method is also not my answer simply because we don't have multiple inheritance in C# and it is different from having a default implementation for interfaces (if possible!).

Lillia answered 19/5, 2015 at 9:42 Comment(4)
Java has recently re-introduced multiple inheritance via defining implementations in interfaces, as you say. This is truly ironic as Java was instrumental in introducing interfaces as a way of combating feared problems with multiple inheritance in the first place. C# hasn't done this though and so single-inheritance (if you really must use inheritance) remains all C# supports..Poster
This may change in the C# 8, see discussion on GitHubLawsuit
This feature is already in preview release for c# - devblogs.microsoft.com/dotnet/…Somerset
@DavidArno Most of the problems from "classical" multiple inheritance is due to shared state. Default interface implementations do not introduce any new state.Genteelism
L
58

C# v8 and above allows concrete implementation for methods in interfaces as well. Earlier it was allowed only for abstract classes.

This change will now shield our concrete classes from side-effects of changing the interface after it has been implemented by a given class e.g. adding a new contract in the interface after the DLL has already been shipped for production use. So our class will still compile properly even after adding a new method signature in the interface being implemented.

This is now possible because we can also provide a default implementation for the new contract being introduced. Thus, we will not have to change any old or existing classes who are using this interface (Refer code snippet).

interface IA
{
    void NotImplementedMethod(); //method having only declaration
    void M() 
    { 
        WriteLine("IA.M"); 
    }//method with declaration + definition
}

In principle, we can say that C# interfaces have now started behaving like abstract classes.

References:

Lecithinase answered 28/8, 2017 at 5:56 Comment(3)
Would you consider updating this answer given C# > v8. A possible useful reference: learn.microsoft.com/en-us/dotnet/csharp/whats-new/…Flyman
done. Thanks for your nice suggestion.Lecithinase
Thanks... though it still says "will be possible in the next language version" and refers to outdated Github issues. I was thinking more along the lines of updated wording and links.Flyman
C
43

I develop games so I often want to have common function for all implementations of an interface but at the same time allow each implementation to do its own thing as well, much like a subclass' virtual / override methods would function.

This is how I do it:

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) { }
}
Cassondra answered 23/6, 2016 at 0:25 Comment(11)
I don't see any use of IRobotHelper in your example. What's its purpose?Thorn
@Thorn - The proposed architecture offers the ability to have common functionality across interface implementations. IRobotHelper holds the common parts so that each implementation needs only implement the implementation-specific parts. In this example, if you have an object r of type Robocop or WallE, or any other class which implements IRobot, and you call r.Move(1) it will first call the shared function Move(this IRobot) from IRobotHelper, which will in turn call the implementation-specific OnMove(1) of the corresponding implementation of IRobot. Does that make sense to you?Cassondra
Very much so--thank you for the detailed comments and explanation.Thorn
If you are wondering as I was, how is it even possible that Move() get called on IRobot, it is called Extension methodsHoban
IRobotHelper should probably be used instead of IRobot for Robocop & WallE classesDenver
@MarkEntingh IRobotHelper is used for functions which need a default implementation across Robocop & WallE. IRobot is still used for functions which should be present in both classes, but without a default implementation (ie. you may want a Calculate() function for all IRobot classes, but without a default implementation - it would not be present in the IRobotHelper class).Cassondra
Okay now I see what you've done. Using the 'this' keyword in the static method Move affects all robots. IRobotHelper is a static class with an extension method. The part that confused me was the I in IRobotHelper. That class is not an interface, so it probably shouldn't contain the prefix I.Denver
@MarkEntingh exactly ;) The I is there because it's a helper of the class IRobot. I guess that convention conversation would be a topic for a different post though :>Cassondra
@KonstantinosVasileiadis The standard naming would be RobotExtensions. Not that it matters much, of course.Genteelism
@Genteelism thanks for the input! probably best not to change it at this point since it's not going to be updated in the comments below which would still point to the old name.Cassondra
Is the IRobotHelper.Move() method somehow a Proxy? Because you're adding some logic before your Robot implementatios get executed, and Proxy pattern it's exactly that, adding logic before or after other behavior without having to edit the original class.Fulsome
E
19

Short Answer:

No, you cannot write implementation of method in interfaces.

Description:

Interfaces are just like contract ,so that the types that will inherit from it will have to define implementation, if you have a scenario you need a method with default implementation, then you can make your class abstract and define default implementation for method which you want.

For Example:

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

    public abstract string SomeMethodWhichDerivedTypeWillImplement();
}

and now in Dervied class:

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

UPDATE (C# 8 will have support for this):

C# 8 will allow to have default implementation in interfaces

Efik answered 19/5, 2015 at 9:43 Comment(0)
W
8

Not directly, but you can define an extension method for an interface, and then implement it something like this

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* It is important that the extension method and the method that you are implementing are named differently, otherwise you will likely get a stackoverflow.

Wite answered 2/10, 2017 at 19:37 Comment(1)
Using extension methods clutters the "apparent" interface. If you like allowing consumers to choose the "default" or "standard" implementation, then this is a benefit. Normal static methods would avoid this effect. However, they would also make editor add-ins/"code snippets" more complicated as they would need the name of the interface/helper class. Something like return <InterfaceName>Defaults.<MethodName>(this); vs. return this.<MethodName>Default();.Lycaonia
D
8

it is possible in C# 8.0. You can add a method with default implementation. You will have to change your target framework version to latest to use this feature.

Ducan answered 24/1, 2020 at 12:37 Comment(0)
J
2

C# 11 feature - Now official:

Static virtual members in interfaces

Docs saying:

C# 11 and .NET 7 include static virtual members in interfaces.

This feature enables you to define interfaces that include overloaded operators or other static members. Once you've defined interfaces with static members, you can use those interfaces as constraints to create generic types that use operators or other static methods.

So you can:

Define interfaces with static members.

Use interfaces to define classes that implement interfaces with operators defined.

Create generic algorithms that rely on static interface methods.

https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/static-virtual-interface-members

Prerequisites

You'll need to set up your machine to run .NET 7, which supports C# 11

Jeremie answered 14/2, 2023 at 14:14 Comment(0)
T
0

As a newbe C# programmer I was reading through this topic and wondered if the following code example could be of any help (I don't even know if this is the proper way to do it). For me it allows me to code default behavior behind an interface. Note that I used the generic type specifiction to define an (abstract) class.

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();
        }
    }
}
Testaceous answered 27/8, 2018 at 13:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.