Questions tagged [default-interface-member]

A default interface member is a feature introduced in C# 8 which allows an interface to declare a member with a body. Classes which implement the interface are not required to override a default method. Use this tag for questions relating to C# 8's default interface members

Default interface members were introduced in . They are similar to Java's feature.

An interface member can now be specified with a code body, and if an implementing class or struct does not provide an implementation of that member, no error occurs. Instead, the default implementation is used.

Default interface members help in the following scenarios :

  • Interface versioning
  • Interoperation with APIs targeting Android (Java) and iOS (Swift), which support similar features.
  • To implement without requiring multiple inheritance, similar to PHP and Scala traits. Java 8 and later also supports traits through default interface methods
  • Code Reuse in structs (Thanks Eirik Tsarpalis!)

Interface Versioning

This example is adapted from Mads Torgersen's article on Default implementations in interfaces:

Let’s say that we offer the following interface:

interface ILogger
{
    void Log(LogLevel level, string message);
}

And a class that implements it :

class ConsoleLogger : ILogger
{
    public void Log(LogLevel level, string message) { ... }
}

With default members, the interface can be modified without breaking ConsoleLogger :

interface ILogger
{
    void Log(LogLevel level, string message);
    void Log(Exception ex) => Log(LogLevel.Error, ex.ToString());
}

The ConsoleLogger still satisfies the contract provided by the interface: if it is converted to the interface and the new Log method is called it will work just fine - the interface’s default implementation is just called:

public static void LogException(ConsoleLogger logger, Exception ex)
{
    ILogger ilogger = logger; // Converting to interface
    ilogger.Log(ex);          // Calling new Log overload
}

An implementing class that does know about the new member is free to implement it in its own way. In that case, the default implementation is just ignored.

Traits

In an imaginary game, items may inherit from a GameItem class :

public class GameItem    {    }

Let's assume that a potion doesn't have a location, nor does it move :

public class Potion:GameItem{}

A rock may have a location :

public interface ILocatable
{
    public (double x,double y) Location{get;set;}
}

public class Rock:GameItem,ILocatable
{
    public (double x,double y) Location{get;set;}
}

A player or monster can also move. Without traits, one possible solution would be to add the ability to move to GameItem or introduce an intermediate abstract class with that functionality. Modifying GameItem would also affect Rock while the abstract class would introduce a relation that probably isn't appropriate.

This can be solved with the IMovable trait, which can be applied to any type that has a Location property :

public interface IMovable
{
    public abstract (double x,double y) Location{get;set;}
    void Move(double angle,double speed)
    {              
          var x=Location.x + speed*Math.Sin(angle);
          var y=Location.y + speed*Math.Cos(angle);
          Location=(x,y);
    }
}    

That trait can be applied to any class as long as it has a matching Location property:

public class Player:GameItem,ILocatable,IMovable
{
    public (double x,double y) Location{get;set;}
}

public class Monster:GameItem,ILocatable,IMovable
{
    public (double x,double y) Location{get;set;}
}

Trait Example - Reading settings in a container environment

In container-based or serverless applications, one of the most common ways to distribute settings is through environment variables. DIMs can be used to create a trait that retrieves a specific environment variable each time it's called, eg :

interface IGithubSettings
{
    public string CurrentToken  => Environment.GetEnvironmentVariable("GitHubToken");
}

References :

61 questions
-5
votes
1 answer

Can anyone explain what is the default interface implementation in C# 8.0?

I’m quite new to C# 8.0 and I want to know what is the default interface implementation?
Kevin
  • 785
  • 1
  • 4
  • 7
1 2 3 4
5