0

I would like to ask some rather basic question (I presume) the answer to which seems to elude me. In the following code I am trying to load an array with a csv file (; separated) that contains two columns (string Name, int Score). For simplicity I have commented out the loop I want to use to transfer this file onto an array and I am just loading the 2nd element. For some reason unless I use (scoreobj[1] = new HighScore();) I get a null reference. Why do I need to do that? Haven't I already initialized the scoreobj[] object at the beginning?

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsApp1
{
   public class HighScore
   {
      public string Name { get; set; }
      public int Score { get; set; }

      public static void LoadHighScores(string filename)
      {
         string[] scoredata = File.ReadAllLines("C:/Users/User/Desktop/Test.csv");
         HighScore[] scoreobj = new HighScore[scoredata.Length];
         scoreobj[1] = new HighScore();
         scoreobj[1].Name = scoredata[1].Split(';')[0];

         //for (int index = 0; index < scoredata.Length; index++)
         //{
         //   scoreobj[index].Name = scoredata[index].Split(',')[0];
         //   scoreobj[index].Score = Convert.ToInt32(scoredata[index].Split(';')[1]);

         //}

         Console.WriteLine(scoreobj[1].Name);
      }
   }
}
Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
  • 5
    Because just declaring an index of a specific size does not create any element of type `HighScore`. You could even create an instance of a derived class and put it into the exact same array. How would the compilr in this case know which class you want to instantiate? It can´t and thus won´t. So you have to create the instance yourself. But even without a derived class, your constructgor may have paramaters, which compiler can´t guess - e.g. `new HighScore(name, score)`. – MakePeaceGreatAgain Dec 09 '19 at 10:14
  • 4
    This answer describes exactly why you have experienced this behaviour: https://stackoverflow.com/a/15300089/2169762 – Martin Dec 09 '19 at 10:18
  • 2
    `Haven't I already initialized the scoreobj[] object at the beginning` ...yes, you have. But that just initialises the **array**, it doesn't initialise the **contents** (at least not beyond setting some default values for them, which, for classes etc is always null). – ADyson Dec 09 '19 at 10:21
  • 1
    Bear with me on this....I am trying to get into OOP for the past months.... I do realize that I have initialized the object scoreobj with null values and I have reserved a place in memory. Doesnt this mean I have created an instance of the Highscore class? – Dimitris Platis Dec 09 '19 at 10:23
  • I am trying to get the semantics...... Indeed, now I get that the array must contains different objects. I am just confused on the semantics mostly. Is the array considered an object of the Class that contains objects?> – Dimitris Platis Dec 09 '19 at 10:25
  • The why is already explain. For the solution I will recommend : [Array initialization with default constructor](https://stackoverflow.com/questions/4839470/array-initialization-with-default-constructor). – xdtTransform Dec 09 '19 at 10:30
  • 1
    an array is just a collection that can store a bunch of elements of a specific type. Just because you have a bag does not mean you have any potatoes in it, does it? Of course you have to go to the market and put some potatoes in. – MakePeaceGreatAgain Dec 09 '19 at 10:30
  • Oh i get that. Just was confused about the object semantic. I thought the objects in the array were created with null values initially when I initialize the array – Dimitris Platis Dec 09 '19 at 10:34
  • OK for the semantic yes an array is a class ([reference code](https://referencesource.microsoft.com/#mscorlib/system/array.cs)). And the array you define is an instance of that class so an Object in OO semantic. It has properties (length) and methods. But for the sake of simplicity call the array an array. And not array object instance of the Array class. – xdtTransform Dec 09 '19 at 10:37
  • 1
    " I do realize that I have initialized the object scoreobj with null values and I have reserved a place in memory. Doesnt this mean I have created an instance of the Highscore class?" ....no, because `null` means "there's nothing here". If there was an instance of the class, it could not be null. "the objects in the array were created with null values initially"...no, there are no objects to begin with. There are spaces (containing `null`) which can be used to place objects into. `null` is not an object, or an instance of an object. It's the _absence_ of an object (or value). – ADyson Dec 09 '19 at 11:40
  • In the Pro C#7 book that in the cases of objects utilizing the new keyword automatically sets the variable to the default value, null in the case of objects. Am I correct in saying that in the example above the usage of the new keyword instantiates objects within the array (where there was previously null) and these objects have the default null value before I pass on a value? However, I dont have to do that with other types, such as strings, where I can initialize the array and set its length and immediately add string in it via indexing and assigning. – Dimitris Platis Dec 10 '19 at 16:20

2 Answers2

5

Because just declaring an index of a specific size does not create any element of type HighScore,. Instead you just reserve some memory. In other words: just because you have a bag does not put any potatoes in it. You have to go to the market and put potatoes into your bag yourself.

You could even create an instance of a derived class and put it into the exact same array. How would the compiler in this case know which class you want to instantiate?

class Foo { ... }
class Bar { ... }

var array = new Foo[3]; // how would anyone know if you want three Foo-instances or 3 Bar-instances? or a mix?

The compiler can't know which type you want to instantiate and thus won't create those instances. So you have to create the instance yourself.

But even without a derived class, your constructor may have parameters, which compiler can't guess:

class HighScore
{
    public HighScore(string name, int score) { ... }
}

var array = new HighScore[3]; // how to set the parameters for the instances???

That's why your object just contains no instances, but just the types default-value, which is null for reference-types.

MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
1

HighScore[] scoreobj = new HighScore[scoredata.Length]; creates an array of the specified length (scoredata.Length), but containing no objects.

Yo need to assign an object at each index, which could be done as follows:

for (int i = 0; i < scoredata.Length; i++)
{
    scoreobj[i] = new HighScore();
    scoreobj[i].Name = scoredata[i].Split(';')[0];
}
Johnathan Barclay
  • 18,599
  • 1
  • 22
  • 35