C# 8: Default interface method

Translated from John Demetriou's article "C# 8: Default Interface Methods" 1 on August 4, 2018, with some added content

Before C# 8

Today we will talk about the default interface method. Sounds really weird, doesn't it? The interface is only used to define the contract. The implementation class of the interface will have a set of public methods, but the implementation class is given the freedom to implement each method in its own way. So far, if we need to provide an implementation for one or more of these methods, we will use inheritance.
If we hope that this class does not implement all the methods, but only a subset of them, we can abstract these methods and the class itself ( abstract).

For example, we cannot write:

interface IExample
{
    
    
    void Ex1();                                      // 允许
    void Ex2() => Console.WriteLine("IExample.Ex2"); // 不允许(C# 8 以前)
}

We have to replace it with the following abstract class:

abstract class ExampleBase
{
    
    
    public abstract void Ex1();
    public void Ex2() => Console.WriteLine("ExampleBase.Ex2");
}

Fortunately, this is enough to meet most of our needs.

After C# 8

So, is there any change? Why do we need to introduce this new feature? What did we miss and never noticed what we missed?

Diamond problem

Due to Diamond Problem 2 , C# (and many other languages) does not support multiple inheritance. In order to allow multiple inheritance while avoiding the diamond problem, C# 8 introduced default interface methods.

Starting from C# 8, using the default interface method, you can have an interface definition and the default implementation of some or all methods in the definition.

interface IExample
{
    
    
    void Ex1();                                      // 允许
    void Ex2() => Console.WriteLine("IExample.Ex2"); // 允许
}

Therefore, now you can implement an interface with implemented methods, and you can avoid duplication of code in classes that you want to inherit from a specific class (which also contains common methods).

Using the default interface method, the diamond problem has not been solved 100%. This can still happen when a class inherits from two interfaces inherited from the third interface, and all interfaces implement the same method.
In this case, the C# compiler will choose to call the appropriate method based on the current context. If a specific one cannot be inferred, a compilation error will be displayed.

For example, suppose we have the following interface:

interface IA
{
    
    
    void DoSomething();
}

interface IB : IA
{
    
    
    void DoSomething() => Console.WriteLine("I am Interface B");
}

interface IC : IA
{
    
    
    void DoSomething() => Console.WriteLine("I am Interface C");
}

Then, I create a class Dthat implements the above two interfaces , which will cause a compilation error:

//编译器提示:“D”未实现接口成员“IA.DoSomething()”
public class D : IB, IC
{
    
     }

However, if a class Dof its own version of the realization of DoSomethingthe method, the compiler will know which method call:

public class D : IB, IC
{
    
    
    public void DoSomething() => Console.WriteLine("I am Class D");
}

If the Main method code is as follows:

static void Main()
{
    
    
    var x = new D();
    x.DoSomething();
    Console.ReadKey();
}

Run the program, the console window I am Class Doutput: .

Other benefits

Using the default interface implementation of the method, the API provider can extend the existing interface without breaking any part of the legacy code.

Trait mode

Translator's Note:
In computer programming, Trait is a concept used in object-oriented programming, which represents a set of methods that can be used to extend the functionality of a class. 3

Trait pattern is basically a set of methods required by multiple classes.
Prior to this, the Trait pattern in C# was implemented using abstract classes. But because multiple inheritance is not available, implementing the Trait pattern becomes very tricky, so most people either avoid it or get lost in a huge inheritance chain.

However, using the default method implementation in the interface, this will change. We can implement by using the default interface method in the interface, provide a set of methods that need to be owned by the class, and then let these classes inherit this interface.
Of course, any class can override these methods with their own implementation, but in case they don't want to do so, we provide them with a set of default implementations.

The following is the translator's supplement

Specific methods in the interface

The simplest form of the default interface method is to declare a specific method in the interface , which is a method with a body part.

interface IA
{
    
    
    void M() {
    
     Console.WriteLine("IA.M"); }
}

The class that implements this interface does not need to implement its specific methods.

class C : IA {
    
     } // OK

static void Main()
{
    
    
    IA i = new C();
    i.M(); // 输出 "IA.M"
}

Class Cin IA.Mthe final substitution is in IAparticular a method declared M.
Please note that a class can only implement an interface, and does not inherit members from the interface :

C c = new C(); // 或者 var c = new C();
c.M();         // 错误: 类 'C' 不包含 'M' 的定义

But if the class that implements this interface also implements specific methods, the meaning is the same as the general interface:

class C : IA
{
    
    
    public void M() {
    
     Console.WriteLine("C.M"); }
}

static void Main()
{
    
    
    IA i = new C();
    i.M(); // 输出 "C.M"
}

How does the child interface call the method of the parent interface?

This is a question asked by a friend in the blog garden in the comments. At first glance, this question is quite interesting. Will you encounter such a demand in reality? If you think about it, you might actually use it. Here a simple example to demonstrate, in the interface IBto call the parent interface IAmembers method M, as follows:

interface IA
{
    
    
    void M() {
    
     Console.WriteLine("IA.M"); }
}

interface IB : IA
{
    
    
    //void IA.M() { Console.WriteLine("IB.M"); }

    void IB_M() {
    
     M(); }
}

class C : IB {
    
     }

static void Main(string[] args)
{
    
    
    IB i = new C();
    i.IB_M();  // 输出 "IA.M";如果把 IB 中的注释行打开,这里会输出 "IB.M"
}

Author: John Demetriou
Translator: Technical Zemin
Publisher: Technical Verses
links: English text

Public Number: Technical Translation Station


  1. https://www.devsanon.com/c/c-8-default-interface-methods/ C# 8: Default Interface Methods ↩︎

  2. https://mp.weixin.qq.com/s/EZ_jIjT6hYFrhbJ9BZ7Amw diamond problem↩︎

  3. https://en.wikipedia.org/wiki/Trait_(computer_programming) Trait ↩︎

Guess you like

Origin blog.csdn.net/weixin_47498376/article/details/109225942
Recommended