2009-09-11 12 views
11

diesen Code haben ...Gibt es etwas Magie über Readonlycollection

var b = new ReadOnlyCollection<int>(new[] { 2, 4, 2, 2 }); 
b[2] = 3; 

ich einen Compiler-Fehler in der zweiten Zeile. Ich würde einen Laufzeitfehler erwarten, da ReadOnlyCollection<T> Utensilien IList<T> und die this[T] einen Setter in der IList<T> Schnittstelle haben.

Ich habe versucht, die Funktionalität von ReadOnlyCollection zu replizieren, aber das Entfernen des Setter von this[T] ist ein Kompilierungsfehler.

Antwort

16

Die indexer wird mit expliziten umgesetzt Interface-Implementierung, so dass Sie nur in der Lage sein, es zugreifen, wenn Sie tun:

IList<int> b = new ReadOnlyCollection<int>(new[] { 2, 4, 2, 2 }); 
b[2] = 3; 

oder

var b = new ReadOnlyCollection<int>(new[] { 2, 4, 2, 2 }); 
((IList<int>)b)[2] = 3; 

Natürlich wird es dann bei der Ausführung scheitern ...

Diese ganz bewusste und hilfreich ist - es bedeutet, dass, wenn der Compiler weiß, es ist ein ReadOnlyCollection, sind die nicht unterstützte Bits Funktionalität nicht verfügbar Ihnen helfen, Sie von Ausführungszeitfehlern abzulenken.

Es ist ein interessanter und relativ ungewöhnlicher Schritt jedoch, effektiv Implementierung einer Hälfte einer Eigenschaft/Indexer implizit und eine Hälfte explizit.

Im Gegensatz zu meinen früheren Gedanken, ich glaube ReadOnlyCollection<T>tatsächlich explizit den ganzen Indexer implementiert, aber bietet auch einen öffentlichen Nur-Lese-Indexer.Mit anderen Worten, es ist so etwas wie dieses:

T IList<T>.this[int index] 
{ 
    // Delegate interface implementation to "normal" implementation 
    get { return this[index]; } 
    set { throw new NotSupportedException("Collection is read-only."); } 
} 

public T this[int index] 
{ 
    get { return ...; } 
} 
+0

Ok, aber wie repliziere ich die Funktionalität von ReadOnlyCollection mit expliziter Implementierung. Ich sehe nicht, wie Sie eine Methode oder Eigenschaft aus der Schnittstelle entfernen können. –

+0

@EsbenP: Sie können eine Methode nicht aus der Schnittstelle entfernen ... Sie können sie jedoch nur verfügbar machen, wenn der statische Typ der Referenz die Schnittstelle und nicht die Klasse ist, die die Schnittstelle implementiert. –

+0

Ok, wenn ich zwei Indexer haben, einer von ihnen die Umsetzung IList explizit funktioniert es T IList .Dieses [int index] { erhalten { return Quelle [index]; } set { werfen neue NotImplementedException(); } } public T dieses [int index] { erhalten { return Quelle [index]; } } –

2

Es implementiert IList.Items explizit, was es nicht öffentlich macht, und Sie müssen auf die Schnittstelle umwandeln, um seine Implementierung zu erreichen, und implementiert einen neuen Indexer, [...] der stattdessen verwendet wird, welches nur einen get-accessor hat.

Wenn Sie die Auflistung in IList umwandeln, wird Ihr Code kompiliert, wird aber zur Laufzeit nicht ausgeführt.

Leider weiß ich nicht, wie dies in C# zu tun, da einen Indexer in C# Schreiben des this Schlüsselwort beinhaltet die Verwendung, und Sie können dies nicht schreiben:

T IList<T>.this[int index] { get; set; } 
+0

@Lasse: Sie können schreiben, dass - mit entsprechenden Implementierungen. Das Problem ist, dass Sie nicht eine Hälfte explizit und eine Hälfte implizit implementieren können, soweit ich das beurteilen kann. –

+0

Sie müssen nicht, wenn Sie das schreiben können, Sie schreiben den Setter mit nur eine Ausnahme werfen, und dann implementieren Sie eine öffentliche diese [..] Indexer nur mit dem Getter. –

1

Es gibt keine Magie, haben die ReadOnlyCollection nur verschiedene Implementierungen für seine eigene Indexer und der Indexer, der die IList<T>-Schnittstelle implementiert:

public T Item[int index] { get; } 

T IList<T>.Item[int index] { get; set; } 

Wenn Sie werfen Ihre Liste IList<int>, werden Sie einen Laufzeitfehler statt der Kompilierung Fehler:

((IList<int>)b)[2] = 3; 

Edit:
Um den Indexer in der eigenen Klasse zu implementieren, verwenden Sie das this Stichwort:

public T this[int index] { get { ... } } 

T IList<T>.this[int index] { get { ... } set { ... } } 
+0

Das war auch mein Gedanke, aber wenn ich das in meiner eigenen Klasse versuche, implementiert IList wird es nicht kompilieren –

+0

Was ist die Compile-Fehlermeldung? – thecoop

+0

@EsbenP: Um es in einer Klasse zu implementieren, ist die Syntax nicht die gleiche wie die in der Dokumentation gezeigte Signatur. Siehe die obige Bearbeitung. – Guffa