it-swarm.com.de

Warum explizit die Schnittstelle implementieren?

Was genau ist also ein guter Anwendungsfall, um eine Schnittstelle explizit zu implementieren? 

Ist es nur so, dass die Benutzer, die die Klasse verwenden, nicht alle diese Methoden/Eigenschaften in Intellisense betrachten müssen?

116
Master Morality

Wenn Sie zwei Schnittstellen mit derselben Methode und unterschiedlichen Implementierungen implementieren, müssen Sie sie explizit implementieren.

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

    void IDoItSlow.Go()
    {
    }
}
138
Iain

Es ist nützlich, das nicht bevorzugte Mitglied auszublenden. Wenn Sie beispielsweise IComparable<T> und IComparable implementieren, ist es normalerweise angenehmer, die IComparable-Überladung auszublenden, um nicht den Eindruck zu erwecken, dass Sie Objekte verschiedener Typen vergleichen können. Ebenso sind einige Schnittstellen nicht CLS-kompatibel, wie IConvertible. Wenn Sie die Schnittstelle nicht explizit implementieren, können Endbenutzer von Sprachen, die CLS-Kompatibilität erfordern, Ihr Objekt nicht verwenden. (Was sehr katastrophal wäre, wenn die BCL-Implementierer die IConvertible-Mitglieder der Primitive nicht verstecken würden :))

Ein weiterer interessanter Hinweis ist, dass das Verwenden eines solchen Konstrukts normalerweise bedeutet, dass struct, das eine Schnittstelle explizit implementiert, diese nur durch Aufrufen des Schnittstellentyps aufrufen kann. Sie können dies umgehen, indem Sie allgemeine Einschränkungen verwenden:

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

Wird kein int einrahmen, wenn Sie es übergeben.

63
Michael B

Einige zusätzliche Gründe, eine Schnittstelle explizit zu implementieren:

Rückwärtskompatibilität : Falls sich die ICloneable-Schnittstelle ändert, müssen die implementierenden Methodenklassenmitglieder ihre Methodensignaturen nicht ändern.

cleaner code : Es wird ein Compiler-Fehler angezeigt, wenn die Clone-Methode aus ICloneable entfernt wird. Wenn Sie die Methode jedoch implizit implementieren, können Sie ungenutzte 'verwaiste' öffentliche Methoden verwenden

strong typing : Um die Geschichte von Supercat anhand eines Beispiels zu veranschaulichen, wäre dies mein bevorzugter Beispielcode. Durch die Implementierung von ICloneable kann Clone() explizit typisiert werden, wenn Sie es direkt als MyObject-Instanzmitglied aufrufen:

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

  object ICloneable.Clone()
  {
    return this.Clone();
  }
}
36
Wiebe Tijsma

Eine andere nützliche Technik besteht darin, dass die öffentliche Implementierung einer Methode durch eine Funktion einen Wert zurückgibt, der spezifischer ist als in einer Schnittstelle angegeben.

Beispielsweise kann ein Objekt ICloneable implementieren, aber seine öffentlich sichtbare Clone -Methode gibt seinen eigenen Typ zurück.

Ebenso könnte eine IAutomobileFactory eine Manufacture -Methode haben, die eine Automobile zurückgibt, aber eine FordExplorerFactory, die IAutomobileFactory implementiert, könnte eine haben Die Methode Manufacture gibt ein FordExplorer zurück (das von Automobile abgeleitet ist). Code, der weiß, dass er ein FordExplorerFactory hat, könnte FordExplorer -spezifische Eigenschaften für ein Objekt verwenden, das von einem FordExplorerFactory zurückgegeben wird, ohne dass eine Typumwandlung erforderlich ist, während Code, der nur wusste, dass es einige hat Typ von IAutomobileFactory würde einfach mit seiner Rückgabe als Automobile umgehen.

12
supercat

Dies ist auch nützlich, wenn Sie zwei Schnittstellen mit demselben Mitgliedsnamen und derselben Signatur haben, das Verhalten jedoch ändern möchten, je nachdem, wie es verwendet wird. (Ich empfehle nicht, Code wie folgt zu schreiben):

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
vcsjones

Wenn Sie über eine interne Schnittstelle verfügen und die Mitglieder Ihrer Klasse nicht öffentlich implementieren möchten, müssen Sie sie explizit implementieren. Implizite Implementierungen müssen öffentlich sein.

5
Mike Dour

Es kann die öffentliche Schnittstelle sauberer halten, um eine Schnittstelle explizit zu implementieren, d. H. Ihre File-Klasse könnte IDisposable explizit implementieren und eine öffentliche Methode Close() bereitstellen, die für einen Verbraucher sinnvoller ist als Dispose(). 

F # only bietet eine explizite Schnittstellenimplementierung, so dass Sie immer auf die jeweilige Schnittstelle zugreifen müssen, um auf ihre Funktionalität zuzugreifen, was eine sehr explizite (kein Wortspiel) der Schnittstelle zur Folge hat.

5
BrokenGlass

Ein weiterer Grund für die explizite Implementierung ist Wartungsfähigkeit.

Wenn eine Klasse "beschäftigt" wird - ja, es kommt vor, wir haben nicht alle den Luxus, den Code anderer Teammitglieder umzuformulieren - dann zeigt eine explizite Implementierung, dass eine Methode vorhanden ist, die einen Schnittstellenvertrag erfüllt.

Dadurch wird die Lesbarkeit des Codes verbessert.

4
h bob

Ein anderes Beispiel ist System.Collections.Immutable, in dem sich die Autoren entschieden haben, die Methode zu verwenden, um eine bekannte API für Auflistungstypen beizubehalten, während die Teile der Schnittstelle entfernt werden, die für ihre neuen Typen keine Bedeutung haben.

Konkret implementiert ImmutableList<T>IList<T> und somit ICollection<T> ( , damitImmutableList<T> einfacher mit Legacy-Code verwendet werden kann), void ICollection<T>.Add(T item) macht jedoch keinen Sinn für ImmutableList<T>: da das Hinzufügen eines Elements zu einer unveränderlichen Liste erforderlich ist Bestehende Liste nicht ändern, ImmutableList<T> leitet sich auch von IImmutableList<T> ab, dessen IImmutableList<T> Add(T item) für unveränderliche Listen verwendet werden kann.

Im Fall von Add sehen die Implementierungen in ImmutableList<T> folgendermaßen aus:

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();
1
fuglede

Bei explizit definierten Schnittstellen sind alle Methoden automatisch privat. Sie können den Zugriffsmodifizierer ihnen nicht öffentlich machen. Annehmen:

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
Md Shahriar

So können wir eine explizite Schnittstelle erstellen: ... Wenn wir 2 Schnittstelle haben und beide Schnittstellen dieselbe Methode haben und eine einzige Klasse diese 2 Schnittstellen erbt, so hat der Compiler beim Aufruf einer Schnittstellenmethode die Methode verwirrt aufgerufen werden, damit wir dieses Problem mithilfe der expliziten Schnittstelle lösen können .. Hier ein Beispiel, das ich unten gegeben habe.

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
Debendra Dash