C # 8: método de interfaz predeterminado

Traducido del artículo de John Demetriou "C # 8: Métodos de interfaz predeterminados" 1 el 4 de agosto de 2018, con contenido agregado

Antes de C # 8

Hoy hablaremos sobre el método de interfaz predeterminado. Suena realmente extraño, ¿no? La interfaz solo se utiliza para definir el contrato. La clase de implementación de la interfaz tendrá un conjunto de métodos públicos, pero la clase de implementación tiene la libertad de implementar cada método a su manera. Hasta ahora, si necesitamos proporcionar una implementación para uno o más de estos métodos, usaremos la herencia.
Si esperamos que esta clase no implemente todos los métodos, sino solo un subconjunto de ellos, podemos abstraer estos métodos y la propia clase ( abstract).

Por ejemplo, no podemos escribir:

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

Tenemos que reemplazarlo con la siguiente clase abstracta:

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

Afortunadamente, esto es suficiente para satisfacer la mayoría de nuestras necesidades.

Después de C # 8

Entonces, ¿hay algún cambio? ¿Por qué necesitamos introducir esta nueva función? ¿Qué nos perdimos y nunca notamos lo que nos perdimos?

Problema del diamante

Debido al problema de Diamond 2 , C # (y muchos otros lenguajes) no admite la herencia múltiple. Para permitir la herencia múltiple y evitar el problema del diamante, C # 8 introdujo métodos de interfaz predeterminados.

A partir de C # 8, utilizando el método de interfaz predeterminado, puede tener una definición de interfaz y la implementación predeterminada de algunos o todos los métodos en la definición.

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

Por lo tanto, ahora puede implementar una interfaz con métodos implementados y puede evitar la duplicación de código en las clases que desea heredar de una clase específica (que también contiene métodos comunes).

Usando el método de interfaz predeterminado, el problema del diamante no se ha resuelto al 100%. Esto todavía puede suceder cuando una clase hereda de dos interfaces heredadas de la tercera interfaz y todas las interfaces implementan el mismo método.
En este caso, el compilador de C # elegirá llamar al método apropiado según el contexto actual. Si no se puede inferir uno específico, se mostrará un error de compilación.

Por ejemplo, supongamos que tenemos la siguiente interfaz:

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

Luego, creo una clase Dque implementa las dos interfaces anteriores , lo que provocará un error de compilación:

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

Sin embargo, si una clase tiene Dsu propia versión de la realización del DoSomethingmétodo, el compilador sabrá qué método llama:

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

Si el código del método principal es el siguiente:

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

Ejecute el programa, la I am Class D:.salida de la

Otros beneficios

Usando la implementación de interfaz predeterminada del método, el proveedor de API puede extender la interfaz existente sin romper ninguna parte del código heredado.

Modo de rasgo

Nota del traductor:
En programación de computadoras, Trait es un concepto usado en programación orientada a objetos, que representa un conjunto de métodos que pueden usarse para extender la funcionalidad de una clase. 3

El patrón de rasgos es básicamente un conjunto de métodos requeridos por múltiples clases.
Antes de esto, el patrón Trait en C # se implementó usando clases abstractas. Pero debido a que la herencia múltiple no está disponible, implementar el patrón Trait se vuelve muy complicado, por lo que la mayoría de la gente lo evita o se pierde en una enorme cadena de herencia.

Sin embargo, al usar la implementación del método predeterminado en la interfaz, esto cambiará. Podemos implementar usando el método de interfaz predeterminado en la interfaz, proporcionar un conjunto de métodos que deben ser propiedad de la clase y luego dejar que estas clases hereden esta interfaz.
Por supuesto, cualquier clase puede anular estos métodos con su propia implementación, pero en caso de que no quieran hacerlo, les proporcionamos un conjunto de implementaciones predeterminadas.

El siguiente es el suplemento del traductor.

Métodos específicos en la interfaz

La forma más simple del método de interfaz predeterminado es declarar un método específico en la interfaz , que es un método con una parte del cuerpo.

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

La clase que implementa esta interfaz no necesita implementar sus métodos específicos.

class C : IA {
    
     } // OK

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

La clase Cen IA.Mla sustitución final es, en IAparticular, un método declarado M.
Tenga en cuenta que una clase solo puede implementar una interfaz y no hereda miembros de la interfaz :

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

Pero si la clase que implementa esta interfaz también implementa métodos específicos, el significado es el mismo que el de la interfaz general:

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

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

¿Cómo llama la interfaz secundaria al método de la interfaz principal?

Esta es una pregunta que hizo un amigo en el jardín del blog en los comentarios. A primera vista, esta pregunta es bastante interesante. ¿Encontrará tal demanda en la realidad? Si lo piensas bien, es posible que lo uses. Aquí un ejemplo simple para demostrar, en la interfaz IBpara llamar al IAmétodo de miembros de la interfaz principal M, como sigue:

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"
}

Autor: John Demetriou
Traductor: Technical Zemin
Editor: Technical Verses
enlaces: texto en inglés

Número público: Estación de traducción técnica


  1. https://www.devsanon.com/c/c-8-default-interface-methods/ C # 8: Métodos de interfaz predeterminados ↩︎

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

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

Supongo que te gusta

Origin blog.csdn.net/weixin_47498376/article/details/109225942
Recomendado
Clasificación