Ein Unterschied im Stil: IDictionary vs. Dictionary

Lesezeit: 7 Minuten

Ich habe einen Freund, der gerade erst in die .NET-Entwicklung einsteigt, nachdem er jahrelang in Java entwickelt hat, und nachdem ich mir einige seiner Codes angesehen habe, stelle ich fest, dass er ziemlich oft Folgendes tut:

IDictionary<string, MyClass> dictionary = new Dictionary<string, MyClass>();

Er deklariert das Wörterbuch als Schnittstelle und nicht als Klasse. Normalerweise würde ich folgendes tun:

Dictionary<string, MyClass> dictionary = new Dictionary<string, MyClass>();

Ich würde die IDictionary-Schnittstelle nur verwenden, wenn sie benötigt wird (z. B. um das Wörterbuch an eine Methode zu übergeben, die eine IDictionary-Schnittstelle akzeptiert).

Meine Frage ist: Hat seine Art, Dinge zu tun, irgendwelche Vorzüge? Ist dies eine gängige Praxis in Java?

  • Für lokale Variablen gibt es wirklich keinen Sinn.

    – Joren

    20. Oktober 2009 um 15:49 Uhr

  • Dupe: stackoverflow.com/questions/1484445/…

    – mmx

    20. Oktober 2009 um 17:33 Uhr

  • Eine gute Praxis ABER Achtung Leistungskosten: nimaara.com/2016/03/06/beware-of-the-idictionary-tkey-tvalue

    – Majan

    6. März 2016 um 18:39 Uhr


  • Die beiden wichtigsten Implementierungen von IDictionary (Dictionary und ConcurrentDictionary) haben sehr unterschiedliche Leistungsmerkmale (z Count ist auf ersterem sehr schnell und auf letzterem sehr langsam). Daher würde ich empfehlen, die konkrete Klasse anzugeben (anstatt IDictionary) nach Möglichkeit in C#, damit der Verbraucher weiß, wie er das Wörterbuch auf performante Weise verwenden kann.

    – Testamente

    18. September 2017 um 7:25 Uhr

  • Zusätzlich, IDictionary hat einige Performance-‘Macken’ – nimaara.com/2016/03/06/beware-of-the-idictionary-tkey-tvalue .

    – Testamente

    3. Januar 2019 um 11:11 Uhr

Benutzer-Avatar
Chris

Wenn IDictionary ein “generischerer” Typ als Dictionary ist, ist es sinnvoll, den allgemeineren Typ beim Deklarieren von Variablen zu verwenden. Auf diese Weise müssen Sie sich nicht so sehr um die Implementierungsklasse kümmern, die der Variablen zugewiesen ist, und Sie können den Typ in Zukunft einfach ändern, ohne viel folgenden Code ändern zu müssen. Zum Beispiel wird es in Java oft als besser angesehen

List<Integer> intList=new LinkedList<Integer>();

als es zu tun ist

LinkedList<Integer> intList=new LinkedList<Integer>();

Auf diese Weise bin ich sicher, dass der gesamte folgende Code die Liste als Liste und nicht als LinkedList behandelt, was es in Zukunft einfach macht, LinkedList für Vector oder jede andere Klasse, die List implementiert, auszutauschen. Ich würde sagen, das ist Java und guter Programmierung im Allgemeinen gemeinsam.

  • +1, aber vielleicht möchten Sie das Wort “allgemein” anstelle von “generisch” verwenden, das bereits eine Menge Bedeutung hat 🙂

    – AakashM

    20. Oktober 2009 um 15:49 Uhr

Diese Praxis ist nicht nur auf Java beschränkt.

Es wird auch häufig in .NET verwendet, wenn Sie die Instanz des Objekts von der verwendeten Klasse entkoppeln möchten. Wenn Sie die Schnittstelle statt der Klasse verwenden, können Sie den Unterstützungstyp jederzeit ändern, ohne den Rest Ihres Codes zu beschädigen.

Sie werden auch feststellen, dass diese Vorgehensweise häufig beim Umgang mit IoC-Containern und der Instanziierung mithilfe des Factory-Musters verwendet wird.

  • Aber Sie verlieren alle Funktionen, die Dictionary möglicherweise bietet und die nicht in IDictionary enthalten sind.

    – Zügel

    20. Oktober 2009 um 15:37 Uhr

  • Aber wenn Sie stattdessen IDictionary verwenden können … verwenden Sie die Funktionalität zunächst nicht.

    – Justin Nießner

    20. Oktober 2009 um 15:38 Uhr

  • Aber wenn Sie nur die Funktionalität in IDictionary benötigen … Es ist einfacher, IDictionary in Dictionary zu ändern als umgekehrt 🙂

    – Svis

    20. Oktober 2009 um 15:38 Uhr

  • Es ist einfacher, ein Wörterbuch in ein IDictionary umzuwandeln als umgekehrt. 🙂

    – Zügel

    20. Oktober 2009 um 15:40 Uhr

  • Der springende Punkt dieser Redewendung ist der Verlust der Funktionalität, die Dictionary bietet, IDictionary jedoch nicht. Wenn Sie Ihre lokale Variable als IDictionary deklarieren, müssen Sie Ihre Verwendung dieser Variablen auf das beschränken, was über die Schnittstelle verfügbar ist. Wenn Sie später feststellen, dass Sie eine andere Klasse verwenden müssen, die IDictionay anstelle von Dictionary implementiert, können Sie dies tun, indem Sie die eine Zeile ändern, die den konkreten Klassenkonstruktor aufruft (da Sie wissen, dass Ihr Code ihn nur als IDictionary verwendet, nicht als Dictionary ).

    – Stephen C. Stahl

    20. Oktober 2009 um 17:33 Uhr

Benutzer-Avatar
Vitalij Liptchinsky

Ihr Freund folgt dem sehr nützlichen Prinzip:

“Abstrahieren Sie sich von Implementierungsdetails”

  • Aber wir beschäftigen uns mit Implementierungsdetails. Wir erstellen keine Schnittstelle zu einer Klasse – wir deklarieren einfach eine lokale Variable.

    – Zügel

    20. Oktober 2009 um 15:48 Uhr

  • Nicht wirklich, IMHO. Wenn Ihnen Interface-Mitglieder ausreichen, würde ich Ihnen wirklich empfehlen, bei Interface zu bleiben. Machen Sie Ihren Code so allgemein wie möglich.

    – Vitaliy Liptchinsky

    20. Oktober 2009 um 19:31 Uhr

Sie sollten immer versuchen, die Schnittstelle und nicht die konkrete Klasse zu programmieren.

In Java oder einer anderen objektorientierten Programmiersprache.

In der .NET-Welt ist es üblich, eine zu verwenden I um anzuzeigen, dass es sich um eine Schnittstelle handelt, die Sie verwenden. Ich denke, das ist häufiger, weil sie es in C# nicht haben implements und extends um auf die Vererbung von Klasse und Schnittstelle zu verweisen.

Ich denke, Whey würde tippen

 class MyClass:ISome,Other,IMore 
 { 
 }

Und das merkt man ISome ein IMore sind Schnittstellen während Other ist eine Klasse

In Java ist so etwas nicht nötig

 class MyClass extends Other implements Some, More {
 }

Das Konzept gilt immer noch, Sie sollten versuchen, die Schnittstelle zu programmieren.

Für lokale Variablen und private Felder, die bereits Implementierungsdetails sind, ist es besser, konkrete Typen als Schnittstellen für die Deklarationen zu verwenden, da die konkreten Klassen einen Leistungsschub bieten (direkter Versand ist schneller als virtueller/Schnittstellenversand). Das JIT kann Methoden auch einfacher inline integrieren, wenn Sie in den lokalen Implementierungsdetails nicht unnötig in Schnittstellentypen umwandeln. Wenn eine Instanz eines konkreten Typs von einer Methode zurückgegeben wird, die eine Schnittstelle zurückgibt, erfolgt die Umwandlung automatisch.

  • Das ist eine Mikrooptimierung, die nur durchgeführt werden sollte, wenn Sie einen bestimmten Leistungsengpass lösen müssen, sie sollte nicht das Design vorantreiben.

    – Yishai

    20. Oktober 2009 um 18:40 Uhr

  • Es ist keine Mikrooptimierung. Sie befinden sich bereits in der Umsetzung, wo Sie sich für eine konkrete Umsetzung entschieden haben. Warum so tun, als hätten Sie es nicht auf Kosten der Leistung getan?

    – Sam Harwell

    21. Oktober 2009 um 13:41 Uhr

Benutzer-Avatar
Travis Hesemann

Am häufigsten sehen Sie den Schnittstellentyp (IDictionary), der verwendet wird, wenn der Member für externen Code verfügbar gemacht wird, unabhängig davon, ob sich dieser außerhalb der Assembly oder direkt außerhalb der Klasse befindet. In der Regel verwenden die meisten Entwickler den konkreten Typ intern für eine Klassendefinition, während sie eine gekapselte Eigenschaft mithilfe des Schnittstellentyps verfügbar machen. Auf diese Weise können sie die Fähigkeiten des konkreten Typs nutzen, aber wenn sie den konkreten Typ ändern, muss sich die Schnittstelle der deklarierenden Klasse nicht ändern.

public class Widget
{
    private Dictionary<string, string> map = new Dictionary<string, string>();
    public IDictionary<string, string> Map
    {
        get { return map; }
    }
}

später kann werden:


class SpecialMap<TKey, TValue> : IDictionary<TKey, TValue> { ... }

public class Widget
{
    private SpecialMap<string, string> map = new SpecialMap<string, string>();
    public IDictionary<string, string> Map
    {
        get { return map; }
    }
}

ohne die Benutzeroberfläche des Widgets zu ändern und anderen Code, der es bereits verwendet, ändern zu müssen.

  • Das ist eine Mikrooptimierung, die nur durchgeführt werden sollte, wenn Sie einen bestimmten Leistungsengpass lösen müssen, sie sollte nicht das Design vorantreiben.

    – Yishai

    20. Oktober 2009 um 18:40 Uhr

  • Es ist keine Mikrooptimierung. Sie befinden sich bereits in der Umsetzung, wo Sie sich für eine konkrete Umsetzung entschieden haben. Warum so tun, als hätten Sie es nicht auf Kosten der Leistung getan?

    – Sam Harwell

    21. Oktober 2009 um 13:41 Uhr

Benutzer-Avatar
Gergely Orosz

Soweit ich gesehen habe, verwenden Java-Entwickler häufiger Abstraktion (und Entwurfsmuster) als .NET-Entwickler. Dies scheint ein weiteres Beispiel dafür zu sein: Warum die konkrete Klasse deklarieren, wenn er im Wesentlichen nur mit den Schnittstellenmitgliedern arbeiten wird?

  • Ich war bis zum zweiten Satz bei dir. Wie sonst soll man sich einen Verweis auf einen Interface-Implementierer verschaffen? Sie müssen etwas instanziieren, das es implementiert. new IDictionary<string, double>() würde nicht funktionieren und macht sowieso keinen Sinn.

    –Tom W

    12. Juli 2011 um 17:32 Uhr


  • Ich verstehe nicht wirklich … mein Punkt war, dass jeder, der jemals das Wörterbuchmitglied verwendet, nur IDictionary-Funktionen verwenden möchte. Offensichtlich müssen Sie etwas instanziieren, aber wenn Sie dieses Muster verwenden, bedeuten die folgenden Codes dasselbe für jeden, der die Klasse verwendet: IDictionary dictionary = new Dictionary(); und IDictionary Wörterbuch = new ConcurrentDictionary(); Wenn Sie keine Dictionary- oder ConcreteDictionary-spezifischen Member verwenden, ist es sinnvoll, sie nicht als Typ der Klassenvariablen zu deklarieren und eine Abstraktionsebene hinzuzufügen.

    – Gergely Orosz

    13. Juli 2011 um 8:28 Uhr


1229300cookie-checkEin Unterschied im Stil: IDictionary vs. Dictionary

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy