Krótkie pytanie. Tworzę swoją własną kolekcję - klasę, która ma jakąś tam listę w sobie, i przeładowuje operator [] i inne takie. Czy mogę coś przeładować, zaimplementować, cokolwiek, abym tworząc obiekt tej klasy mógł używać operatora { } aby na starcie dodać elementy do własnej kolekcji. Tak jak się to robi np. w listach: List<int> mojaLista = new List<int>() {1, 2, 3, 4, 5}
On napisał(a)
Czy mogę coś przeładować, zaimplementować, cokolwiek, abym tworząc obiekt tej klasy mógł używać operatora { }
Możesz zaimplementować swój kompilator, który Ci na to pozwoli. :)
Dodam sobie nowe zadanie do kalendarza ;). Dzięki za odpowiedź :)
Nie trzeba tworzyć własnego kompilatora, to normalny mechanizm języka. Klasa List
nie jest w żadnym stopniu „magiczna”.
Sam mechanizm jest prosty: metoda Add()
, której zadaniem jest dodanie elementu. Ciągnie to jednak za sobą konieczność zaimplementowania interfejsu IEnumerable, opcjonalnie IEnumerable<T>, a to dalej – wyczarowanie z kolekcji iteratora, albo napisanie własnego.
Kodu robi się dużo, ale skoro robisz własną kolekcję, to i tak to wszystko powinieneś mieć zaimplementowane...
using System;
using System.Collections;
using System.Collections.Generic;
class Kolekszyn<T>:IEnumerable<T>
{
// nasza kolekcja jest tylko opakowaniem na tablicę
const int max_rozmiar = 256;
T[] tablica;
int indeks = 0;
public Kolekszyn()
{
tablica = new T[max_rozmiar];
}
public int Length
{
get { return indeks; }
}
// za obsługę klamer odpowiada metoda Add
public void Add(T a)
{
if (indeks==max_rozmiar)
throw new InvalidOperationException("za dużo");
tablica[indeks++] = a;
}
// indekser
public T this[int indeks]
{
get { return tablica[indeks]; }
set { tablica[indeks] = value; }
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return (IEnumerator<T>) new KolekszynEnum<T>(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator) new KolekszynEnum<T>(this);
}
}
class KolekszynEnum<T>:IEnumerator<T>
{
Kolekszyn<T> kolekcja;
int indeks = -1;
public KolekszynEnum(Kolekszyn<T> akolekcja)
{
kolekcja = akolekcja;
}
object IEnumerator.Current
{
get { return kolekcja[indeks]; }
}
T IEnumerator<T>.Current
{
get { return kolekcja[indeks]; }
}
bool IEnumerator.MoveNext()
{
return (++indeks < kolekcja.Length);
}
void IEnumerator.Reset()
{
indeks = -1;
}
void IDisposable.Dispose()
{
}
}
class program
{
static void Main()
{
var kol = new Kolekszyn<int> {1,2,3,4,5,6,7,8,9,10};
foreach (int i in kol)
Console.WriteLine(i);
}
}
Ciekawa sprawa, nigdy właściwie o tym nie czytałem, aż chciałem sprawdzić to wczoraj samemu :). Dzięki za ciekawostkę!
No proszę, C# mnie ciągle zadziwia, dzięki. :) Zawsze w takiej sytuacji robiłem znacznie brzydsze:
new List<int>(new[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
edit: Ale żeby nie było za pięknie - mamy w C# taki piękny choć dziwnie brzmiący keyword yield
. Niepotrzebnie kombinujesz z tym enumeratorem...
Zamień na to a KolekszynEnum wywal:
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
for(int i = 0; i < indeks; i++)
yield return tablica[i];
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<T>)(this)).GetEnumerator();
}
Mój błąd, nie wiedziałem nawet, że tak się da. Na dodatek błąd podwójny, bo nie doczytałem i zrozumiałem, że autor szuka czegoś takiego: Kolekszyn<int> k = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
, a tego to chyba bez zmiany kompilatora się nie da.
Dzięki wszystkim za odpowiedź. Najfajniejsze jest to, że trochę nieświadomie, już to wszystko zaimplementowałem, a potem nie zauważyłem, że z rozmachu użyłem tego sposobu na tworzenie obiektu mojej klasy. Później, już nie pisząc nic, wpadł mi pomysł do głowy, że to może być fajne ;]. No i wyszło jak wyszło. Teraz przynajmniej rozumiem. Pozdrawiam, dzięki jeszcze raz.