2009-09-11 15 views
11

Mając ten kod ...Czy jest coś magicznego ReadOnlyCollection

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

otrzymuję błąd kompilacji w drugiej linii. Spodziewam się błędu runtime, ponieważ ReadOnlyCollection<T> implementuje IList<T>, a this[T] ma ustawnik w interfejsie IList<T>.

Próbowałem replikować funkcjonalność ReadOnlyCollection, ale usunięcie settera z this[T] jest błędem kompilacji.

Odpowiedz

16

indexer realizowany jest jawne implementacja interfejsu, więc można tylko do niego dostęp, jeśli zrobić:

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

lub

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

Oczywiście, będzie to wówczas nie w czasie wykonywania ...

Jest to całkowicie zamierzone i pomocny - to oznacza, że ​​gdy kompilator wie to ReadOnlyCollection, nieobsługiwane bity funkcjonalności nie są dostępne dla ciebie, pomagając odciągnąć cię od niepowodzenia czasu wykonania.

Jest to interesujący i stosunkowo nietypowy krok, jednak skutecznie implementowanie pośrednio jednej własności/indeksera, a jedna połowa jawnie.

przeciwieństwie do moich poprzednich myśli, wierzę ReadOnlyCollection<T>faktycznie wdraża cały podziałowe wyraźnie, ale również zapewnia publiczną readonly podziałowe.Innymi słowy, jest to coś takiego:

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, ale w jaki sposób mogę replikować funkcjonalność ReadOnlyCollection za pomocą jawnej implementacji. Nie widzę sposobu, w jaki można usunąć metodę lub właściwość z interfejsu. –

+0

@EsbenP: Nie można usunąć metody z interfejsu ... ale można ją udostępnić tylko wtedy, gdy statyczny typ odwołania jest interfejsem, a nie klasą implementującą interfejs. –

+0

Ok, jeśli mam dwie indeksujących, jeden z nich wdrożenie IList wyraźnie działa T IList .To [int index] { dostać { źródło Powrót [indeks]; } zestaw { rzucić nowe NotImplementedException(); } } T publicznego w [Int indeks] { się { powrotu sieci [indeks]; } } –

2

Implementuje jawnie IList.Items, co czyni go niepublicznym, a będziesz musiał rzucić do interfejsu, aby osiągnąć jego implementację, i implementuje nowy [...] indeksator, który jest używany zamiast tego, który ma tylko get-accessor.

Jeśli wyrzucisz kolekcję do IList, Twój kod zostanie skompilowany, ale zakończy się niepowodzeniem w środowisku wykonawczym.

Niestety nie wiem, jak to zrobić w C#, ponieważ pisanie indeksowania w C# polega na użyciu słowa kluczowego this i nie można zapisać następująco:

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

@Lasse: Można napisać, że - wraz z odpowiednimi wdrożeń. Problem polega na tym, że nie można zaimplementować jednej połowy jawnie i jednej połowy niejawnie, o ile wiem. –

+0

Nie musisz, jeśli możesz to napisać, piszesz settera, tylko rzucając wyjątek, a następnie zaimplementujesz publiczny ten indeksator [...] tylko za pomocą gettera. –

1

Nie ma magii, ReadOnlyCollection tylko mają różne implementacje dla jego własnego indekser i indeksujący, który implementuje interfejs IList<T>:

public T Item[int index] { get; } 

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

Jeśli rzucisz Twoja lista do IList<int>, otrzymasz błąd wykonania zamiast błędu kompilacji:

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

Edit:
celu realizacji podziałowe we własnym klasy, należy użyć this kluczowe:

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

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

To była także moja myśl, ale kiedy spróbuję tego w mojej własnej klasie implementującej IList , to nie skompiluje się –

+0

Co to jest komunikat o błędzie kompilacji? – thecoop

+0

@EbenbenP: Aby zaimplementować go w klasie, składnia nie jest taka sama, jak sygnatura przedstawiona w dokumentacji. Zobacz powyższą edycję. – Guffa

Powiązane problemy