1

I am trying to make a 1d array of lists. I make it like this:

public static List<string>[] words = new List<string>[30];
public static List<string>[] hints = new List<string>[30];

And I call it like this:

foreach (string item in vars.directory)
        {
            reader2 = new StreamReader(item);
            while (reader2.Peek() > 0)
            {
                string line = reader2.ReadLine();
                if (line.StartsWith("#"))
                {
                    vars.words[counter].Add(line.Substring(1, line.Length - 1)); //here
                }
                else if (line.StartsWith("-"))
                {
                    vars.hints[counter].Add(line.Substring(1, line.Length - 1)); //another here
                }
                else if (line == "@end")
                {
                    counter++;
                }
            }
        }

I just wanted to add that vars is where I keep my public variables and that counter is indeed at 0 when the loop starts.

EDIT In my haste I forgot to add the question... oops...

Here it is: When I call the add function (or any another function for that matter) it returns a null reference exception. How can I fix this?

Joel Beckham
  • 18,254
  • 3
  • 35
  • 58
Adam Schiavone
  • 2,412
  • 3
  • 32
  • 65

6 Answers6

7

I assume you're crashing when attempting to call .Add on your array element. You need to initialize your arrays with valid objects.

for( Int32 i = 0; i < vars.words.Length; ++i )
  vars.words[i] = new List<string>();
for( Int32 i = 0; i < vars.hints.Length; ++i )
  vars.hints[i] = new List<string>();
Avilo
  • 1,204
  • 7
  • 7
  • 1
    Since `words` and `hints` are arrays you should use the `Length` property instead of the `Count` method. – jb. Mar 15 '11 at 20:01
  • I always wondered about this, is there a "normal" way to initialize all the array at once ? – OopsUser Mar 15 '11 at 20:01
  • I put that in and I get: Operator '<' cannot be applied to operands of type 'int' and 'method group'. should I replace count with length? – Adam Schiavone Mar 15 '11 at 20:02
  • 1
    @Oops: There is no direct syntax support, but you can get short-and-sweet syntax with Linq: `List[] lists = Enumerable.Range(0, 5).Select(i => new List()).ToArray();` (formatting - I'd put each of those extra method calls on their own line) – Merlyn Morgan-Graham Mar 15 '11 at 20:04
  • @Avilo This works perfectly with 'Length' instead of 'Count' I will mark it correct as soon as it will let me. – Adam Schiavone Mar 15 '11 at 20:05
  • 1
    @Adam8797, change `vars.words.Count` to `vars.words.Length`. Same for `hints` – jb. Mar 15 '11 at 20:05
  • Yes sorry, Length in this instance. Fixed! – Avilo Mar 15 '11 at 20:08
6

Why not just make a List<List<string>>, but yes you can make an array of lists

msarchet
  • 15,104
  • 2
  • 43
  • 66
2

Using a list of lists, as already recommended, would make you escape your problems, and it´s much more flexible and handy than your construction.

-> f.i. if the size of your data changes, you don´t have to change the list size, but the array

AGuyCalledGerald
  • 7,882
  • 17
  • 73
  • 120
0

You could initialize the lists right before you use them:

foreach (string item in vars.directory)
{
    reader2 = new StreamReader(item);
    while (reader2.Peek() > 0)
    {
        string line = reader2.ReadLine();
        // new code
        if (vars.words[counter] == null) vars.words[counter] = new List<string>();
        if (vars.hints[counter] == null) vars.hints[counter] = new List<string>();

        if (line.StartsWith("#"))
        {
            vars.words[counter].Add(line.Substring(1, line.Length - 1)); //here
        }
        else if (line.StartsWith("-"))
        {
            vars.hints[counter].Add(line.Substring(1, line.Length - 1)); //another here
        }
        else if (line == "@end")
        {
            counter++;
        }
    }
}
Joel Beckham
  • 18,254
  • 3
  • 35
  • 58
  • He may have more than a single word or hint to store in each list so each initializer would need to be run only when the element is null. – Avilo Mar 15 '11 at 20:10
0

Here's a one-liner to initialize an array of lists of size 30:

    static List<string>[] lists = (from i in Enumerable.Range(0, 30)
                                   select new List<string>()).ToArray();
jeroenh
  • 26,362
  • 10
  • 73
  • 104
0

The problem is that array values are initialized to the default value, and the default value for reference types is null.

default(List<string>) returns null.

So, you'll need to re-initialize the objects in the array before you can access them, otherwise you will get a NullReferenceException.

One way to initialize all the objects in your array up front is to use this Linq statement:

const int sizeOfLists = 5;
List<string>[] lists = Enumerable.Range(0, sizeOfLists)
    .Select(i => new List<string>())
    .ToArray();

Another option is to initialize and add the sub-lists only when you need them, by using an outer List:

var lists = new List<List<string>>();
// ...
var aSubList = new List<string>();
lists.Add(aSubList);

This is particularly useful if you don't know the size of the outer set of lists up-front, and is still accessible by index.

(This was a comment before, but I made it an answer since many other answers got caught up in the solution and don't describe the problem)

Merlyn Morgan-Graham
  • 58,163
  • 16
  • 128
  • 183