1

I'm working on a library to use in a card game. I spent a couple of hours learning indexers so I could have a Deck class that functions like an array of Card types. Then I achieved the same thing and a whole lot more by inheriting from ArrayList. I therefore ask why one would go to the trouble of making a class indexable when the same thing (and much more) can be achieved via ": ArrayList".

I think my question is pretty self explanatory, but for those who like to look at code.

Here is my Deck class that contains an indexer:

class DeckIndexer
{
    private Card[] myData;
    private int arrSize;



public DeckIndexer(int size)
{
    arrSize = size;
    myData = new Card[size];

    for (int i = 0; i < size; i++)
    {
        myData[i] = null;
    }
}

public Card this[int pos]
{
    get
    {
        return myData[pos];
    }
    set
    {
        myData[pos] = value;
    }
}

public Card this[Card c]
{
    get
    {
        int count = 0;

        for (int i = 0; i < arrSize; i++)
        {
            if (myData[i] == c)
            {
                count++;
            }
        }
        return c;
    }
    set
    {
        for (int i = 0; i < arrSize; i++)
        {
            if (myData[i] == c)
            {
                myData[i] = value;
            }
        }
    }
  }
}

Now here is the second solution, inheriting from ArrayList

  class DeckInheritence : ArrayList
  {

  }

The second solution gives me 20+ methods for free, [] syntax, and saves me however many lines of code. The first gives me [] syntax, the methods attached to object, and is hard to implement.

BTW, yes I can see that ArrayList is giving me an array of objects, not cards, but there is not much fudging to get it to require a Card type.

1
  • arrSize can be replaced with myData.Length, no need to have it twice Commented Nov 25, 2011 at 16:24

2 Answers 2

2

Fundamentally a Deck is not an ArrayList or a List<Card>. Do you want callers to be able to add as many cards as they want to it? I doubt it. How about null or duplicate values? Again, unlikely to be useful.

This is a perfect situation for using composition instead of inheritance. I wouldn't use an array directly within the type - I'd use a List<T> - but you almost certainly want to write more domain-specific code for your deck. There are obvious constraints, deck-specific operations etc. Do you really want to be able to access any item in the deck? I would expect you to want to be able to deal a deck to players, and shuffle it, for example.

The goal should be to create a type which represents your domain as appropriately as possible - not to give you an indexer with the fewest lines of code.

Sign up to request clarification or add additional context in comments.

1 Comment

Interesting advice Jon. I'll meditate on that heh. I'm not really at the stage in my programming yet where I think too much about preventing what an object can do. I guess I just figure if I don't need the methods I wont use them heh. Of course I am the only one who uses my classes so that's probably why I have a misguided view. Thanks.
1

Firstly, unless you are in .NET 1.1, List<Card> would be preferable. However, as for inheriting... if all you are doing is representing a list of cards, I would just use List<Card> (with neither encapsulation nor inheritance).

As for the why; encapsulation is useful when being a list is not the primary purpose of a type, but it is useful for the caller to have access to a few methods like indexers. As Jon notes, inheriting doesn't (for example) give you any control over what the user does to your data.

Personally, I don't recommend inheriting from List<T> (or ArrayList); that binds an implementation detail into the actual type declaration (changing inheritance is a breaking change).

If you want to expose lots of methods with minimal work, all you need to do is provide IEnumerable<T> (as an interface) - then all of LINQ becomes available. So if you need something bespoke (more than List<Card>) my advice would be:

  • encapsulate List<T> (i.e. a private field)
  • implement IEnumerable<T> if appropriate (just return theList.GetEnumerator())
  • add any specific members you want (indexers etc)

1 Comment

OK. I'll try just that. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.