Własna kolekcja - klasa i operator { }

1

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}

3
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. :)

2

Dodam sobie nowe zadanie do kalendarza ;). Dzięki za odpowiedź :)

4

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);
  }
}
2

Ciekawa sprawa, nigdy właściwie o tym nie czytałem, aż chciałem sprawdzić to wczoraj samemu :). Dzięki za ciekawostkę!

3

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();
}
2

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.

1

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.

1 użytkowników online, w tym zalogowanych: 0, gości: 1