[C#]Custom Collection of een Generic Collection

Pagina: 1
Acties:
  • 613 views sinds 30-01-2008
  • Reageer

Onderwerpen


Acties:
  • 0 Henk 'm!

  • TeeDee
  • Registratie: Februari 2001
  • Laatst online: 14-09 22:43
In een inmiddels lichtelijk uit de hand gelopen discussie over het gebruik van een CustomCollection vs een Generic Collection wil ik hier toch nog even de meningen peilen.

Ik ben van mening dat "AddressCollection" (IEnumerable) in dit specifieke geval beter is dan een Generic variant. Waarom? AddressCollection bevat een n-aantal objecten van het Type Address. Mijns inziens is een Generic variant precies datgene wat voor Generics staat. Een collectie met Generieke objecten (int, Address, string etc. etc.).

De andere partij van de discussie vind dit niet want: "Een Generic collection is lekker makkelijk, want daar kan je alles in stoppen."
(wat hij vind moet hij trouwens bij de politie brengen ;))

Nu ben ik het daar niet mee eens, want mijn stelling is:

- Ik heb een Address object
- Dat stop ik logischerwijs in een AddressCollection
- Ik weet dat ik daar niks anders in hoef te stoppen.

Onderstaand wat voorbeeld classes.
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Address
{
    public Address()
    {}
    public Address(string street,string name)
    {
        Street = street;
        Name = name;
    }
    private string _straat = "";
    private string _naam = "";
    public string Street
    {
        get { }
        set { }
    }
    public string Name
    {
        get { }
        set { }
    }
}
en de Collection
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class AddressCollection : IEnumerable
{
    private ArrayList alist = new ArrayList();
    public Address this[int AddressID]
    {
        get { return (Address)alist[AddressID]; }
        set { alist[AddressID] = value; }
    }

    public int Add(Address value)
    {
        return alist.Add(value);
    }
    public void Remove(Address value)
    {
        alist.Remove(value);
    }
    public void RemoveAt(int index)
    {
        alist.RemoveAt(index);
    }
    public int Count
    {
        get { return alist.Count; }
    }
    public IEnumerator GetEnumerator()
    {
        return alist.GetEnumerator();
    }
}

Hoe zijn de meningen hierover?

Heart..pumps blood.Has nothing to do with emotion! Bored


Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Een generic collection definieer je toch zo dat er maar een bepaald type in kan?

Dus dan krijg je ArrayList<Address> vs. AddressCollection.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

Verwijderd

Waarom zou je je eigen class schrijven terwijl het prachtig in een Generic kan, die zijn overigens gewoon strong typed hoor (daar kun je echt niet van alles in stoppen).

List<object> daar gelaten natuurlijk maar dat is imho een worst practice.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 10:23
Volgens hetgeen ik nu lees, denk ik dat jij denkt (:P) dat er in een Generic Collection objecten kunnen geplaatst worden van meerdere (niet gerelateerde) types ?

Zoals Michali al zegt, definieer je bij het definieren van je generic collection welk type objecten die generic collection kan bevatten.
In dit geval dus objecten van het type Adress (en objecten die overerven van het type Adress)
Ik zie dus niet in waarom je hier de moeite zou willen doen om een eigen custom collection te gaan bouwen ?

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • TeeDee
  • Registratie: Februari 2001
  • Laatst online: 14-09 22:43
Michali, thekip: ik zie nu ook in dat dat inderdaad kan.

Punt is, is dat die Collection een overblijfsel is uit een heel oud project, en ik bleef het maar gebruiken. Vandaar.
whoami schreef op donderdag 08 november 2007 @ 12:20:
Volgens hetgeen ik nu lees, denk ik dat jij denkt (:P) dat er in een Generic Collection objecten kunnen geplaatst worden van meerdere (niet gerelateerde) types ?
:Y
* TeeDee gaat zich maar eens beter verdiepen in Generics.
Zoals Michali al zegt, definieer je bij het definieren van je generic collection welk type objecten die generic collection kan bevatten.
In dit geval dus objecten van het type Adress (en objecten die overerven van het type Adress)
Ik zie dus niet in waarom je hier de moeite zou willen doen om een eigen custom collection te gaan bouwen ?
Zal eens even aan de slag gaan.

Dan wordt de collection dus iets als:
C#:
1
ArrayList<Address> AddressCollection;


Het belangrijkste waarom er toen voor zoiets gekozen is, om het e.e.a. op basis van een index aan te spreken.
Nu moet ik eerlijk zeggen dat ik me echt nooit bezig gehouden heb met Generics, dus vandaar mijn onwetendheid.

Maar goed, zo pik je nog wel eens iets op.

Heart..pumps blood.Has nothing to do with emotion! Bored


Acties:
  • 0 Henk 'm!

Verwijderd

Documentatie lezen doet wonderen ;)

Je kunt met een generic class (bv List<Address>) toch ook alles met een index aanspreken?

En mocht je extra functionaliteit willen toevoegen aan je collection, krijg je dit soort constructies:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class AddressCollection : List<Address>
{
    public AddressCollection() { }
    public AddressCollection(IEnumerable<Address> collection) : base(collection) { }
    public AddressCollection(int capacity) : base(capacity) { }

    public IEnumerable<Address> FindAllByStreet(string street)
    {
        return FindAll(new Predicate<Address>(
            delegate(Address item)
            {
                return item.Street == street;
            }));
    }
}

Ik noem maar wat ;)

Acties:
  • 0 Henk 'm!

  • TeeDee
  • Registratie: Februari 2001
  • Laatst online: 14-09 22:43
Zo, even het e.e.a. ingelezen, bekeken en heel snel eventjes wat in elkaar geslingerd.
Het is inderdaad simpeler om bijvoorbeeld een List<Address> e.d. te gebruiken dan een eigen Custom Collection.

Wat gaat dit mijn leven een stuk makkelijker maken zeg.

* TeeDee moet voor straf de gehele dag koffie halen en voor de lunch ben ik ook de sjaak. Bedankt allemaal ;)

Heart..pumps blood.Has nothing to do with emotion! Bored


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:28

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op donderdag 08 november 2007 @ 19:22:
En mocht je extra functionaliteit willen toevoegen aan je collection, krijg je dit soort constructies:
Onhandige constructies, to say the least. Dit betekent dat je óf van tevoren voor elke mogelijke collectie een eigen class moet gaan maken, óf op een later moment een dergelijke collectie toe moet gaan voegen waardoor je alle huidige code aan moet gaan passen (een andere optie is om de hele tijd data rond te kopiëren, maar dat wil je ook niet).

Maak dan gewoon een setje utility functies die op een ICollection<Address> of IEnumerable<Address> werken, dan verplicht je code niet een bepaalde class te gebruiken om bepaalde functionaliteit te krijgen.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

Verwijderd

.oisyn schreef op vrijdag 09 november 2007 @ 10:59:
Onhandige constructies, to say the least. Dit betekent dat je óf van tevoren voor elke mogelijke collectie een eigen class moet gaan maken, óf op een later moment een dergelijke collectie toe moet gaan voegen waardoor je alle huidige code aan moet gaan passen (een andere optie is om de hele tijd data rond te kopiëren, maar dat wil je ook niet).

Maak dan gewoon een setje utility functies die op een ICollection<Address> of IEnumerable<Address> werken, dan verplicht je code niet een bepaalde class te gebruiken om bepaalde functionaliteit te krijgen.
Ik gebruik collecties niet enkel als lijst, maar ook om bewerkingen op een lijst uit te kunnen voeren. Die interfaces (IList, ICollection, IEnumerable) zijn er niet voor niets en die collection classes zijn niet voor niets niet sealed.

Waarom wel rechtstreeks Clear op een collectie aanroepen, maar niet Clear met een aantal parameters? Ik ben er altijd voor om code logisch te groeperen. Kopieren van code is vaak niet nodig als je een goede hiërarchie van je collecties gebruikt.

Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Volgens mij begrijp je niet wat .oisyn bedoelt.

Hij heeft het niet over het aanroepen van een methode met of zonder parameters, maar de plek waar deze methode is geïmplementeerd. Je zegt tevens dat interfaces zoals IList en ICollection er niet voor niets zijn, echter is dat juist het punt dat .oisyn probeerde te maken, maar waar jij in je code geen rekening mee houdt. Je kunt de betreffende code namelijk alleen uitvoeren op een object van de klasse AddressCollection wat tevens (door de inheritance) een List<Address> is. Hierdoor sluit je andere implementaties van IList<Address> af, want die kunnen hier geen gebruik van maken.

Beter is het daarom om een utility klasse te maken die de bewerking op een parameter van het type IList<Address> uitvoert. Kopiëren van code is in jouw geval dus sneller nodig dan wanneer je deze manier van werken aanhoudt.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

Verwijderd

Ik zou het zelf gewoon met Collection doen, of eventueel met ReadOnlyCollection als het een niet bewerkbare collectie betreft en dan daarin de list gebruiken. Voor zover als ik het begrijp kan een list die je aan de buitenwereld toont je later in de problemen brengen, bijv als je opeens iets wil doen bij het wissen of aanmaken van nieuwe items in de collectie. Tevens zitten er aardig wat methoden in List<T> die ik niet altijd nodig heb voor een collectie.

Bijv.
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    public class AddressCollection : Collection<Address>
    {
        public AddressCollection() : base(new List<Address>())
        {
        }

        // ik zou niet weten hoe ik dit doe als het een List is, 
        // zonder dat gebruikers er last van ondervinden
        protected override void RemoveItem(int index)
        {
            Trace.Write("oh oh we zijn items aan het wissen uit de collectie");
            base.RemoveItem(index);
        }

        // evt. alleen find functie, die is vaak wel makkelijk =)
        public Address Find(Predicate<Address> match)
        {
            List<Address> items = (List<Address>)Items;
            return items.Find(match);
        }
    }
   

Acties:
  • 0 Henk 'm!

Verwijderd

Michali schreef op zaterdag 10 november 2007 @ 11:15:
Je zegt tevens dat interfaces zoals IList en ICollection er niet voor niets zijn, echter is dat juist het punt dat .oisyn probeerde te maken, maar waar jij in je code geen rekening mee houdt. Je kunt de betreffende code namelijk alleen uitvoeren op een object van de klasse AddressCollection wat tevens (door de inheritance) een List<Address> is. Hierdoor sluit je andere implementaties van IList<Address> af, want die kunnen hier geen gebruik van maken.

Beter is het daarom om een utility klasse te maken die de bewerking op een parameter van het type IList<Address> uitvoert. Kopiëren van code is in jouw geval dus sneller nodig dan wanneer je deze manier van werken aanhoudt.
Mijn reactie sloeg juist op wat .oisyn en jij bedoelt: de plek waar je dergelijke methoden neerzet. Niet in een "utility class" als je het mij vraagt.

Stel je wilt een item handmatig opzoeken, dan gebruik je Find() met een predicate. Stel je hebt een bepaalde match die je vaker gebruikt (bv FindById(Guid)). Nu, waar zet je die method neer? In een "utility class"? Je hebt dan Find in de ene class, en FindById in een hele andere. Wat ik in zulke gevallen doe, die overigens erg vaak voorkomen, is FindById toevoegen als method aan de collectie. Eventueel, als het nodig is, met een static variant met een parameter voor de lijst in IEnumerable<T> formaat. Met laatstgenoemde generic interface kun je alle soorten collecties meegeven; flexibeler dan IList<T> dus.

Zo hou je alles netjes bij elkaar, wat weer de raison d'être is van object georiënteerd programmeren. Ook gebruik je static methods nu goed.

Acties:
  • 0 Henk 'm!

  • MaxxRide
  • Registratie: April 2000
  • Laatst online: 22-06 16:52

MaxxRide

Surf's up

Er heeft een artikel over in het .NET magazine gestaan:

http://download.microsoft...c2f5af7/p45-47_1%2016.pdf

Hopelijk heb je hier nog wat aan.

If you are not wiping out you are nog pushing enough...


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:28

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op vrijdag 16 november 2007 @ 19:05:
Eventueel, als het nodig is, met een static variant met een parameter voor de lijst in IEnumerable<T> formaat. Met laatstgenoemde generic interface kun je alle soorten collecties meegeven; flexibeler dan IList<T> dus.

Zo hou je alles netjes bij elkaar, wat weer de raison d'être is van object georiënteerd programmeren. Ook gebruik je static methods nu goed.
En dát is dus precies waar ik op doel. Een losse functie die op een generieke collectie van bepaalde elementen kan worden losgelaten, en dus geen instance method waarvoor je een instantie van een specifieke class nodig hebt terwijl dat eigenlijk niet nodig is. Dat je dat soort functies groepeert in bijvoorbeeld een AddressContainer class is logisch aangezien je ze in C# nou eenmaal niet los kunt definieren, maar waar het om gaat is dat je dergelijke methoden overal in je applicatie kunt gebruiken, ookal heb je de ene keer een List<Address> en de andere keer een Address[]. Zodra je echter verplicht om een AddressContainer instantie te hebben om dat soort operaties te kunnen gebruiken breng je jezelf echter alleen maar in de problemen, omdat dat niet meer werkt op een List<Address> die je elders in je applicatie wellicht hebt rondslingeren (waardoor je óf de code aan moet passen óf de hele tijd kopieën moet gaan zitten maken van je data)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1