0

I'm getting a stack overflow from using the get/set part of my index. I've tried putting the values into a list instead in the get set but with bad results.

class TrackList : CollectionBase
{
    public Tracks this[int i]
    {
        get
        {
            return this[i];
        }
        set
        {
            this[i] = value;
        }
    }
}

Main:

class Program
{
    public static void Main(string[] args)
    {
        TrackList l1 = new TrackList();
        l1[0] = new Tracks(1, "Random");
        l1[1] = new Tracks(2, "Random");
        l1[2] = new Tracks(3, "Random");
    }
}

Answer: I was looping inside my get/set. Here is the working code:

class TrackList : CollectionBase
{
    public Tracks this[int i]
    {
        get
        {
            return (Tracks) List[i];
        }
        set
        {
            List[i] = value;
        }
    }
}

Main:

class Program
{
    public static void Main(string[] args)
    {
        TrackList l1 = new TrackList();
        l1.Add(new Tracks(1, "random"));
        l1.Add(new Tracks(2, "random"));
        l1.Add(new Tracks(3, "random"));
    }
}
Rohkin
  • 13
  • 2

2 Answers2

3

You are recursively calling the property indexer an infinite number of times. I think you want this:

public Tracks this[int i]
{
    get
    {
        return (Tracks) List[i];
    }
    set
    {
        List[i] = value;
    }
}

Then, add your items:

TrackList l1 = new TrackList();
l1.List.Add(new Tracks(1, "Random"));
l1.List.Add(new Tracks(2, "Random"));
l1.List.Add(new Tracks(3, "Random"));

Then replace an item using the indexer:

l1[1] = new Tracks(2, "Replacement");

Or retrieve an item using the indexer:

var firstItem = l1[0];

Trying to use l1[i] where i <= l1.Count will produce an ArgumentOutOfRangeException, as you would expect.

Ant P
  • 24,820
  • 5
  • 68
  • 105
  • 1
    collectionBase does not provide an indexer – Persi Apr 17 '14 at 12:03
  • When I put that in I get this back: Cannot apply indexing with [] to an expression of type 'System.Collections.CollectionBase' – Rohkin Apr 17 '14 at 12:04
  • @AntP you must use List.Insert(i, value) otherwise it will throw an exception – amnezjak Apr 17 '14 at 12:17
  • @Ant P When I changed List[i] = value; to List.Add(value); it worked! Thanks for the help! – Rohkin Apr 17 '14 at 12:19
  • @Rohkin `List[i] = value` is something completely different to `List.Add(value)`. Add always adds the element at end of list *extending* the list instead changing an element in it. – BlueM Apr 17 '14 at 12:23
  • Add always inserts on next available index, not the one provided by indexer. To fully implement this kind of indexer more sophisticated code is necessary – amnezjak Apr 17 '14 at 12:24
  • @amnezjak like i said this is for a school exercise to get us familliar with the indexer, but thanks for the input. – Rohkin Apr 17 '14 at 12:26
  • @Rohkin Then you didn't understand the indexer yet. – BlueM Apr 17 '14 at 12:28
  • @amnezjak I don't think `Insert` is appropriate since it will not replace what exists at the specified index (unintuitive behaviour). What would be more appropriate is to use the indexer above but to first `Add` them using `l1.List.Add`. – Ant P Apr 17 '14 at 12:29
  • Using `list.Add` is for sure incorrect in the indexer setter. – BlueM Apr 17 '14 at 12:30
  • @Rohkin I'm just saying this code doesn't fullfil your school excercise requirements – amnezjak Apr 17 '14 at 12:31
  • @Ant P Thank you for the explanation, I understand how I was misusing the indexer. – Rohkin Apr 17 '14 at 12:40
0

First, your stackoverflow exception is caused by calling your indexer on itself:

    return this[i];

You call your indexer which calls your indexer which then calls your indexer and so on.

Your main program should look like this:

class Program
{
    public static void Main(string[] args)
    {
        TrackList l1 = new TrackList();
        l1.Add(new Tracks(1, "Random"));
        l1.Add(new Tracks(2, "Random"));
        l1.Add(new Tracks(3, "Random"));
    }
}

You can't just access indexes which not yet exist in your list.

After you added its ok to get a certain element from it:

Tracks t = l1[2]; // to get the third element in your list

DO NOT use list.Add in an indexer setter. This violates the least astonishment principle.

Otherwise the only possibility is to create a list with predefined number of null elements in your constructor. But I don't recommend this.

TrackList l1 = new TrackList(3); // in constructor create a list of 3 null elements

The correct way for the whole approach is using List<Tracks> and you are done.

BlueM
  • 6,523
  • 1
  • 25
  • 30
  • `Add` is an explicit implementation on `CollectionBase`; this won't compile unless `l1` has a compile-time type of `IList` or `TrackList` implements `IList` itself. – Ant P Apr 17 '14 at 12:43
  • I wonder what the exercise task is behind what he has to do and why he derives from CollectionBase. – BlueM Apr 17 '14 at 12:46
  • I'm presuming that it's some contrived task asking him to "implement an indexer on the following class" or something similar. I can't see any real-world value to doing this given the existence of generic collections. – Ant P Apr 17 '14 at 12:48