Warum explizite Schnittstellenimplementierung?
Frage
Ich implementierte vor kurzem eine Klasse wie:
class TestClass : IDisposable
{
RegistryKey m_key;
public TestClass()
{
m_key = Registry.CurrentUser.OpenSubKey("Software", false);
}
public void Dispose()
{
// m_key.Dispose();
IDisposable disp = m_key;
disp.Dispose();
}
}
Wenn ich den direkten Aufruf Kommentar- Verfügungs, erhalte ich Fehler CS0117 ( „‚Microsoft.Win32.RegistryKey‘enthält keine Definition für‚entsorgen‘“). Einige Googeln führte mich href="http://bytes.com/groups/net-c/521478-interface-implementation" rel="noreferrer"> dieses Themas MSDN Dokumentation schlägt vor, dass der Autor würde es vorziehen, dass ich nenne Close () anstelle von Dispose (), aber nicht erklären, warum.
Was ist der Zweck dieses Musters (was ich denke, ich habe es in den IO-Klassen als auch zu sehen)? In Anbetracht der Tatsache, dass dies eine absichtliche Entscheidung der Klasse Autor war, wie schlecht ist der Code oben (der Aufruf der IDisposable-Schnittstelle zu entsorgen durch)? Es kann nicht so schlimm sein - schließlich ist es das, was in einer using-Anweisung geschehen würde, rechts
[Änderungen: 1) geändert Titel von "non-public" auf "explicit" 2) entfernt, um die explizite Implementierung von meinem Code versehentlich links in von Experimenten]
Lösung
Das nennt man explizite Schnittstellenimplementierung . In Ihrem Beispiel, da Sie die Methode Dispose () als „ungültig IDisposable.Dispose ()“ definieren Sie die IDisposable-Schnittstelle als auch explizit zu implementieren.
Dies geschieht normalerweise um Kollisionen zu vermeiden. Wenn Microsoft jemals eine andere Methode Dispose () hinzufügen wollte, die etwas anderes zu RegistryKey täte, würde sie nicht in der Lage sein, wenn sie nicht explizit Umsetzung dieser Schnittstelle verwendet.
Dies geschieht oft mit dem generischen IEnumerable
public clas SomeClass : IEnumerable<SomeOtherClass>
{
public IEnumerator<SomeOtherClass> GetEnumerator ()
{
...
}
IEnumerator IEnumerable.GetEnumerator ()
{
return GetEnumerator ();
}
}
Auf diese Weise, wenn Sie ein Objekt von Someclass des GetEnumator Methode aufrufen, ruft die generische Version, da die andere ausdrücklich umgesetzt wurde, so dass wir die starken eingeben Generika bekommen können.
Siehe Seiten 166-169 von Programmierung C # von Jesse Liberty (ich die vierte Ausgabe haben).
Andere Tipps
Die meisten Menschen mit mir nicht einverstanden ist, aber Ich mag mit expliziter Schnittstellenimplementierung für alle Schnittstellen . Ich möchte klarstellen, ob ich eine Methode Schreiben auf mein Objekt oder auf meine Schnittstelle aufgerufen werden.
Das ist schmerzhaft, wenn Sie einen Verweis auf das Objekt und wollen eine Schnittstelle Methode aufzurufen (wie im obigen Beispiel), aber ich mildere sie durch Schreiben:
class C : IDisposable
{
public IDisposable IDisposable { get { return this; } }
void IDisposable.Dispose() { }
}
was bedeutet, dass die Methode auf C Aufruf wie folgt aussieht:
C c = ...
c.IDisposable.Dispose();
Der Compiler parst dies als „Rufen Sie die IDisposable
Eigenschaft auf C, dann rufen Sie die Dispose()
Methode auf das Ergebnis“ aber ich lese es als „Rufen Sie die IDisposable.Dispose()
Methode auf C
“, die hier natürlich erscheint.
Dieser Ansatz kann hässlich, wenn generische Schnittstellen, leider.