¿Por qué implementar interfaz explícitamente?


Entonces, ¿cuál es exactamente un buen caso de uso para implementar una interfaz explícitamente?

¿Es solo para que las personas que usan la clase no tengan que mirar todos esos métodos/propiedades en intellisense?

 116
Author: gdoron, 2010-11-05

11 answers

Si implementa dos interfaces, ambas con el mismo método y diferentes implementaciones, entonces tiene que implementar explícitamente.

public interface IDoItFast
{
    void Go();
}
public interface IDoItSlow
{
    void Go();
}
public class JustDoIt : IDoItFast, IDoItSlow
{
    void IDoItFast.Go()
    {
    }

    void IDoItSlow.Go()
    {
    }
}
 139
Author: Iain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-05 03:11:28

Es útil ocultar el miembro no preferido. Por ejemplo, si implementas IComparable<T> y IComparable normalmente es mejor ocultar la sobrecarga IComparable para no dar a la gente la impresión de que puedes comparar objetos de diferentes tipos. Del mismo modo, algunas interfaces no son compatibles con CLS, como IConvertible, por lo que si no implementa explícitamente la interfaz, los usuarios finales de idiomas que requieren el cumplimiento de CLS no pueden usar su objeto. (Lo que sería muy desastroso si los implementadores de BCL no ocultaran Miembros iconvertibles de los primitivos:))

Otra nota interesante es que normalmente el uso de una construcción de este tipo significa que la estructura que implementa explícitamente una interfaz solo puede invocarlos mediante el boxeo al tipo de interfaz. Puedes evitar esto usando restricciones genéricas::

void SomeMethod<T>(T obj) where T:IConvertible

No boxeará un int cuando le pases uno.

 62
Author: Michael B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-21 16:46:54

Algunas razones adicionales para implementar una interfaz explícitamente:

Compatibilidad hacia atrás: En caso de que la interfaz ICloneable cambie, los miembros de la clase de método de implementación no tienen que cambiar sus firmas de método.

Cleaner code: habrá un error de compilador si el método Clone se elimina de ICloneable, sin embargo, si implementa el método implícitamente, puede terminar con métodos públicos 'huérfanos' no utilizados

Escritura fuerte: Ilustrar la historia de supercat con un ejemplo, este sería mi código de ejemplo preferido, implementando ICloneable explícitamente permite que Clone() se escriba fuertemente cuando lo llamas directamente como miembro de la instancia MyObject:

public class MyObject : ICloneable
{
  public MyObject Clone()
  {
    // my cloning logic;  
  }

  object ICloneable.Clone()
  {
    return this.Clone();
  }
}
 36
Author: Wiebe Tijsma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-06 11:45:12

Otra técnica útil es hacer que la implementación pública de una función de un método devuelva un valor que es más específico que el especificado en una interfaz.

Por ejemplo, un objeto puede implementar ICloneable, pero todavía tiene su método Clon públicamente visible que devuelve su propio tipo.

Del mismo modo, una IAutomobileFactory podría tener un método de Fabricación que devuelve un automóvil, pero una FordExplorerFactory, que implementa IAutomobileFactory, podría tener su método de Fabricación devuelve un FordExplorer (que deriva de Automobile). El código que sabe que tiene una FordExplorerFactory podría usar propiedades específicas de FordExplorer en un objeto devuelto por una FordExplorerFactory sin tener que encasillar, mientras que el código que simplemente sabía que tenía algún tipo de IAutomobileFactory simplemente se ocuparía de su retorno como un Automóvil.

 13
Author: supercat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-28 17:28:14

También es útil cuando tiene dos interfaces con el mismo nombre de miembro y firma, pero desea cambiar el comportamiento de la misma en función de cómo se utiliza. (No recomiendo escribir código como este):

interface Cat
{
    string Name {get;}
}

interface Dog
{
    string Name{get;}
}

public class Animal : Cat, Dog
{
    string Cat.Name
    {
        get
        {
            return "Cat";
        }
    }

    string Dog.Name
    {
        get
        {
            return "Dog";
        }
    }
}
static void Main(string[] args)
{
    Animal animal = new Animal();
    Cat cat = animal; //Note the use of the same instance of Animal. All we are doing is picking which interface implementation we want to use.
    Dog dog = animal;
    Console.WriteLine(cat.Name); //Prints Cat
    Console.WriteLine(dog.Name); //Prints Dog
}
 7
Author: vcsjones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-05 03:14:16

Si tiene una interfaz interna y no desea implementar los miembros de su clase públicamente, los implementaría explícitamente. Las implementaciones implícitas deben ser públicas.

 5
Author: Mike Dour,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-05 03:14:32

Puede mantener la interfaz pública más limpia para implementar explícitamente una interfaz, es decir, su clase File podría implementar IDisposable explícitamente y proporcionar un método público Close() que podría tener más sentido para un consumidor que Dispose().

F# solo ofrece una implementación de interfaz explícita por lo que siempre tiene que enviar a la interfaz en particular para acceder a su funcionalidad, lo que hace un uso muy explícito (sin juego de palabras) de la interfaz.

 5
Author: BrokenGlass,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-05 03:16:53

Otra razón para la implementación explícita es para mantenibilidad.

Cuando una clase está "ocupada"yes sí, sucede, no todos tenemos el lujo de refactorizar el código de otros miembros del equipo.entonces tener una implementación explícita deja claro que un método está ahí para satisfacer un contrato de interfaz.

Por lo que mejora la "legibilidad"del código.

 4
Author: h bob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-26 14:11:12

En el caso de interfaces explícitamente definidas, todos los métodos son automáticamente privados, no se les puede dar el modificador de acceso público. Supongamos que:

interface Iphone{

   void Money();

}

interface Ipen{

   void Price();
}


class Demo : Iphone, Ipen{

  void Iphone.Money(){    //it is private you can't give public               

      Console.WriteLine("You have no money");
  }

  void Ipen.Price(){    //it is private you can't give public

      Console.WriteLine("You have to paid 3$");
  }

}


// So you have to cast to call the method


    class Program
    {
        static void Main(string[] args)
        {
            Demo d = new Demo();

            Iphone i1 = (Iphone)d;

            i1.Money();

            ((Ipen)i1).Price();

            Console.ReadKey();
        }
    }

  // You can't call methods by direct class object
 0
Author: Md Shahriar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-17 12:33:42

Así es como podemos crear una Interfaz explícita: Si tenemos 2 interfaces y ambas tienen el mismo método y una sola clase heredan estas 2 interfaces por lo que cuando llamamos a un método de interfaz el compilador se confundió a qué método llamar, por lo que podemos manejar este problema utilizando una Interfaz Explícita. He aquí un ejemplo que he dado a continuación.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace oops3
{
    interface I5
    {
        void getdata();    
    }
    interface I6
    {
        void getdata();    
    }

    class MyClass:I5,I6
    {
        void I5.getdata()
        {
           Console.WriteLine("I5 getdata called");
        }
        void I6.getdata()
        {
            Console.WriteLine("I6 getdata called");
        }
        static void Main(string[] args)
        {
            MyClass obj = new MyClass();
            ((I5)obj).getdata();                     

            Console.ReadLine();    
        }
    }
}
 0
Author: Debendra Dash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-16 14:07:13

Un ejemplo diferente es dado por System.Collections.Immutable, en el que los autores optaron por usar la técnica para preservar una API familiar para los tipos de colección mientras raspaban las partes de la interfaz que no tienen significado para sus nuevos tipos.

Concretamente, ImmutableList<T> implementa IList<T> y así ICollection<T> ( para permitir que ImmutableList<T> se use más fácilmente con código heredado), sin embargo, void ICollection<T>.Add(T item) no tiene sentido para un ImmutableList<T>: dado que agregar un elemento a una lista inmutable no debe cambiar la lista existente, ImmutableList<T> también se deriva de IImmutableList<T> cuyo IImmutableList<T> Add(T item) puede ser usado para listas inmutables.

Así, en el caso de Add, las implementaciones en ImmutableList<T> terminan como sigue:

public ImmutableList<T> Add(T item)
{
    // Create a new list with the added item
}

IImmutableList<T> IImmutableList<T>.Add(T value) => this.Add(value);

void ICollection<T>.Add(T item) => throw new NotSupportedException();

int IList.Add(object value) => throw new NotSupportedException();
 0
Author: fuglede,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-01 18:41:19