[Visual C#] The Hauntings of NullArgumentException

Started by
9 comments, last by Zahlman 14 years, 10 months ago
I have been haunted by the ghost of NullArgumentException. Basically the program I am making is a game menu. It has functions to take a new username and password and write them to files to save them for the next running of the program. However, when I try and run the program when there are no current usernames or passwords, it fails because the file is null(?). This is the function which results in the NullArgumentException: (three blocks of code - one for each character slot)

// ----------------------- SHOW THE NAMES
    static void ShowNames()
    {
        System.IO.StreamReader reader;        

        reader = new System.IO.StreamReader(name1);
        string str1 = reader.ReadLine();
        char[] char1 = str1.ToCharArray();
        if (char1.Length != 0)
            System.Console.WriteLine("| 1. ", str1, "|");
        else System.Console.WriteLine("| 1. Empty slot        |");


        reader = new System.IO.StreamReader(name2);
        string str2 = reader.ReadLine();
        char[] char2 = str1.ToCharArray();
        if (char1.Length != 0)
            System.Console.WriteLine("| 1. ", str2, "|");
        else System.Console.WriteLine("| 1. Empty slot        |");


        reader = new System.IO.StreamReader(name3);
        string str3 = reader.ReadLine();
        char[] char3 = str1.ToCharArray();
        if (char1.Length != 0)
            System.Console.WriteLine("| 1. ", str3, "|");
        else System.Console.WriteLine("| 1. Empty slot        |");

    }



What the function is meant to do is read all the three username files, and then convert the string result into an array of characters. Then, if the length of the array is 0, I assume no username has been set, so it prints empty slot. Otherwise it prints the string from the file. I have been told that it can be solved by declaring new readers at the top, but this didn't work and kinda resulted in more complications. Here is the whole program (228 lines) if you need it:

// ------------------------------------------------------------------------ CLASS
public class Game
{
    static string[] characters = new string[3];
    static string[] full_characters = new string[3];
    static string[] passwords = new string[3];

    static bool[] ischaracter = new bool[3];
    static bool[] ispassword = new bool[3];

    static System.IO.FileStream name1, name2, name3;
    static System.IO.FileStream pass1, pass2, pass3;



    // --------------------------------------------------------------------- MAIN 
    static void Main(string[] args)
    {

        // ----------------------- START MENU
        System.Console.WriteLine("Welcome to Odyssey!\n");
        System.Console.WriteLine("Choose your character:\n\n");
        System.Console.WriteLine("---------------------");
        System.Console.WriteLine("| Character name    | ");
        System.Console.WriteLine("|-------------------| ");

        Game.ShowNames();

        System.Console.WriteLine("---------------------");


        // ----------------------- TAKE CHARACTER CHOICE AND RESPOND
        string choice = System.Console.ReadLine();
        int choicenum = 0;

        if (choice == "1") choicenum = 1;
        if (choice == "2") choicenum = 2;
        if (choice == "3") choicenum = 3;

        Game.RespondChoice(choicenum);


        // ---------------------- SET NEW PASSWORD


        // ---------------------- TAKE PASSWORD ATTEMPT AND CHECK IT
        string pass_try = System.Console.ReadLine();

        Game.CheckPass(choicenum);
    }

    // ---------------------------------------------------------------- FUNCTIONS

    // ----------------------- SHOW THE NAMES
    static void ShowNames()
    {
        System.IO.StreamReader reader;        

        reader = new System.IO.StreamReader(name1);
        string str1 = reader.ReadLine();
        char[] char1 = str1.ToCharArray();
        if (char1.Length != 0)
            System.Console.WriteLine("| 1. ", str1, "|");
        else System.Console.WriteLine("| 1. Empty slot        |");


        reader = new System.IO.StreamReader(name2);
        string str2 = reader.ReadLine();
        char[] char2 = str1.ToCharArray();
        if (char1.Length != 0)
            System.Console.WriteLine("| 1. ", str2, "|");
        else System.Console.WriteLine("| 1. Empty slot        |");


        reader = new System.IO.StreamReader(name3);
        string str3 = reader.ReadLine();
        char[] char3 = str1.ToCharArray();
        if (char1.Length != 0)
            System.Console.WriteLine("| 1. ", str3, "|");
        else System.Console.WriteLine("| 1. Empty slot        |");

    }

    // ----------------------- FILL THE NAMES TO WIDTH 15
    static void FillChars()
    {
        full_characters[0] = characters[0].PadRight(15);
        full_characters[1] = characters[1].PadRight(15);
        full_characters[2] = characters[2].PadRight(15);
    }

    // ---------------------- RESPOND TO CHARACTER CHOICE
    static void RespondChoice(int i)
    {
        switch (i)
        {
            case 1:
                if (ischaracter[1]) Game.CheckPass(i);
                else Game.NewName(1);
                break;

            case 2:
                if (ischaracter[1]) Game.CheckPass(i);
                else Game.NewName(2);
                break;

            case 3:
                if (ischaracter[2]) Game.CheckPass(i);
                else Game.NewName(3);
                break;
        }
    }
    
    // ---------------------- SET NEW CHARACTER NAME
    static void NewName(int i)
    {
        System.Console.WriteLine("Choose your character's name.\n");

        System.IO.StreamWriter writer;

        switch (i)
        {
            case 1:
                name1 = System.IO.File.OpenWrite("name1.txt");
                writer = new System.IO.StreamWriter(name1);

                characters[0] = System.Console.ReadLine();
                writer.WriteLine(characters[0]);
                writer.Close();
                ischaracter[0] = true;
                break;
            case 2:
                name2 = System.IO.File.OpenWrite("name2.txt");
                writer = new System.IO.StreamWriter(name2);

                characters[1] = System.Console.ReadLine();
                writer.WriteLine(characters[1]);
                writer.Close();
                ischaracter[1] = true;
                break;
            case 3:
                name3 = System.IO.File.OpenWrite("name3.txt");
                writer = new System.IO.StreamWriter(name3);

                characters[2] = System.Console.ReadLine();
                writer.WriteLine(characters[2]);
                writer.Close();
                ischaracter[2] = true;
                break;
        }

        Game.NewPass(i);
    }
    
    // ---------------------- SET NEW PASSWORD
    static void NewPass(int i)
    {

        System.Console.WriteLine("Choose your character's password.\n");

        System.IO.StreamWriter writer;

        switch (i)
        {
            case 1:
                pass1 = System.IO.File.OpenWrite("pass1.txt");
                writer = new System.IO.StreamWriter(pass1);

                passwords[0] = System.Console.ReadLine();
                writer.WriteLine(passwords[0]);
                writer.Close();
                System.Console.WriteLine("You're in.");
                break;
            case 2:
                pass2 = System.IO.File.OpenWrite("pass2.txt");
                writer = new System.IO.StreamWriter(pass2);

                passwords[1] = System.Console.ReadLine();
                writer.WriteLine(passwords[1]);
                writer.Close();
                System.Console.WriteLine("You're in.");
                break;
            case 3:
                pass3 = System.IO.File.OpenWrite("pass3.txt");
                writer = new System.IO.StreamWriter(pass3);

                passwords[3] = System.Console.ReadLine();
                writer.WriteLine(passwords[3]);
                writer.Close();
                System.Console.WriteLine("You're in.");
                break;
        }
    }
    // --------------------- CHECK PASSWORD IS CORRECT
    static void CheckPass(int i)
    {
        string[] attempts = new string[3];

        System.Console.WriteLine("Enter your password:\n");

        System.IO.StreamReader reader;

        switch (i)
        {
            case 1:
                reader = new System.IO.StreamReader(pass1);
                attempts[0] = System.Console.ReadLine();
                if (attempts[0] == reader.ReadLine())
                    System.Console.WriteLine("You're in.");
                else System.Console.WriteLine("Incorrect password.");
                break;
            case 2:
                reader = new System.IO.StreamReader(pass2);
                attempts[1] = System.Console.ReadLine();
                if (attempts[1] == reader.ReadLine())
                    System.Console.WriteLine("You're in.");
                else System.Console.WriteLine("Incorrect password.");
                break;
            case 3:
                reader = new System.IO.StreamReader(pass3);
                attempts[2] = System.Console.ReadLine();
                if (attempts[2] == reader.ReadLine())
                    System.Console.WriteLine("You're in.");
                else System.Console.WriteLine("Incorrect password.");
                break;
        }
    }
}



Any help is greatly appreciated.
Advertisement
We told you in IRC that you need to instantiate your FileStream before you pass it to the StreamReader constructor, which is what is throwing the ArgumentNullException. For example, FileStream name1 = new FileStream(...); Of course, you'll need to insert the appropriate parameters there.
Mike Popoloski | Journal | SlimDX
I thought that was what I had already done at the top of the screen?

With

static System.IO.FileStream name1, name2, name3;


?

Also, I am not trying to read bytes or anything like that. I have never used the constructor with 4 parameters before and have read and written to files fine. I tried adding it at the top but I got all the parameters wrong and it didn't seem to work.

Surely this is not the easiest way? I don't want to read bytes. Just strings.

I made a program before which read and wrote to a file without doing that. =S
static System.IO.FileStream name1, name2, name3;


only creates the variables. It doesn't create the object. Its the same as writing

static System.IO.FileStream name1 = null, name2 = null, name3 = null;

Plane9 - Home of the free scene based music visualizer and screensaver
Yeah, I remember now.

I added this to the start of each of the three blocks:

name1 = System.IO.File.OpenWrite("name1.txt");


but now when I run the program it has an error on the same line as before:

reader = new System.IO.StreamReader(name1);


and it says "Stream was not readable.". Now the error is ArgumentException.

=l
You opened the stream for writing (OpenWrite). How can you read from a stream that you opened for writing? The exception message tells you as much. Try opening it for reading and see if that fixes your problem.
Mike Popoloski | Journal | SlimDX
OK, I changed it, but now it says 'Object reference not set to an instance of an object' and it is NullReferenceException.

I think this would be fixed if I could somehow check if the file contains any information instead of reading it and putting it into a char[] and then checking if that is empty.

But I searched the documentation and I only found a way to search whole directories, suffice it to say it did not work.


First thing you could do is see if the file exists using System.IO.File.Exists(string name).

After that, you can just read from the file and see how many bytes were read.

However, why are you reading from 3 different files? Why not just store all usernames and passwords in 1 file in the combination of user:password

That way, you can just open 'users.ext' and read as many lines are you wish. That solution is not only more scalable in case you wish to add more user accounts in the long term, it's probably also easier to maintain the code for that.

In this case, all you need 1 StreamReader: [NOTE: Below is untested C# code. I wrote this from the top of my head without a compiler, and it's been a while since I used StreamReaders, so don't blame me if there are a few compiler errors.]
if (!File.Exists("users.ext"))    return false; /* or something else, dunno how you're doing this atm */using (StreamReader reader = new StreamReader(new FileStream("users.ext"))){    do    {            string line = reader.ReadLine();        if (line != null) /* do something with line */    } while (line != null)}


Also, why are you using char arrays? C# comes with a String class which is way more suitable for the purpose of handling text. And it's a good idea to use those means from the start, because otherwise you'll learn bad habits.

Toolmaker

[Edited by - Toolmaker on May 31, 2009 7:03:30 PM]

Thank you

I have adapted my code so that ShowNames() now looks like this:

 // ----------------------- SHOW THE NAMES    static void ShowNames()    {       System.IO.StreamReader reader;       if(System.IO.File.Exists("name1.txt"))       {           name1 = System.IO.File.OpenRead("name1.txt");           reader = new System.IO.StreamReader(name1);                      System.Console.WriteLine("| 1. ", reader.ReadLine(), "|");           reader.Close();       }       else System.Console.WriteLine("| 1. Empty slot        |");                if(System.IO.File.Exists("name2.txt"))       {           name2 = System.IO.File.OpenRead("name2.txt");           reader = new System.IO.StreamReader(name2);                        System.Console.WriteLine("| 2. ", reader.ReadLine(), "|" );           reader.Close();       }       else System.Console.WriteLine("| 2. Empty slot        |");         if(System.IO.File.Exists("name3.txt"))       {           name3 = System.IO.File.OpenRead("name3.txt");           reader = new System.IO.StreamReader(name3);                         System.Console.WriteLine("| 3. ", reader.ReadLine(), "|");           reader.Close();       }       else System.Console.WriteLine("| 3. Empty slot        |");     }


Now I can successfully enter a username and password for a slot of my choice.

However:

1. The files all exist, and all contain nothing for some reason, so instead of ever saying 'Empty slot' as I would prefer, it just shows nothing.

2. After saving a username and password, they seem to be reset next time I run the program and don't exist at all.
(1) It's because you use the Console.WriteLine function wrong.
Instead of
System.Console.WriteLine("| 1. ", reader.ReadLine(), "|");

it should be
System.Console.WriteLine("| 1. " + reader.ReadLine() + "|");


The comma character does not concatenate strings, it separates arguments in a function call. Use the + operator for string concatenation.


Edit: (2) You forgot to set ischaracter to true when there is an text file for that character. So one if statement in your ShowNames() method should look like:
if (System.IO.File.Exists("name1.txt")){  name1 = System.IO.File.OpenRead("name1.txt");  reader = new System.IO.StreamReader(name1);  System.Console.WriteLine("| 1. " + reader.ReadLine() + "|");  ischaracter[1] = true;  reader.Close();}else   System.Console.WriteLine("| 1. Empty slot        |");

This topic is closed to new replies.

Advertisement