Hello,

I was wondering if I could get a little guidance regarding an error I keep running into on this assignment. I'm not necessarily looking for any answers as I'd like to complete as much of the assignment myself as possible. However, I've been beating my head against a brick wall on this one error, so if someone can point out why I'm getting this error and what I can do to avoid it, it would be greatly appreciated!

The assignment focuses on argumentExceptions and formatExceptions. In my code, I've been able to provide an output for the correct exceptions, but when attempting to output my results, I get a NullReferenceException in line 39.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Exceptional
{
    class WorkerTest
    {
        static void Main(string[] args)
        {
            Worker[] workerArray = new Worker[5];

            int workerID;
            double hrSal;

            for (int x = 0; x < workerArray.Length; x++)
            {
                try
                {
                    Console.Write("Input a work identification number: ");
                    workerID = Convert.ToInt32(Console.ReadLine());

                    Console.Write("Input an hourly Salary for the worker: ");
                    hrSal = Convert.ToDouble(Console.ReadLine());

                    workerArray[x] = new Worker(workerID, hrSal);
                }

                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }

            }
            Console.WriteLine();
            for (int i = 0; i < workerArray.Length; i++)
            {
                Console.WriteLine("Worker # {0} \nHourly salary {1}\n--------\n ", workerArray[i].workerID, workerArray[i].hrSal.ToString("C"));
            }
        }
    }

    class Worker
    {
        public int workerID;
        public double hrSal;

        public Worker(int WorkerID, double HrSal)
        {
            workerID = WorkerID;
            hrSal = HrSal;

            if (hrSal < 5.0 || hrSal > 55.0)
            {
                workerID = 123;
                hrSal = 7.75;

                throw new ArgumentException("Unexpected Range.");
            }
        }
    }
}

I have attached to this post the requirements for the assignment.

I just copied and ran your program and it worked.

Yeah, it will at first. However, there ends up being a NullReferenceException when I input anything that would be a format exception or an argument exception.

If you input a character instead of an integer value for work identification number or input an hourly salary value that is less than 5 or greater than 55, you'll see what I'm talking about.

Btw - thank you for your quick reply! I've just recently checked out these boards and thus far I'm very impressed by the friendly community!

O.K. I'll try it again.

If you input a character instead of an integer value for work identification number or input an hourly salary value that is less than 5 or greater than 55, you'll see what I'm talking about.

Of course it does, that's what you told it to do.

Line 17-35 is your input loop. In this loop line 27 is what creates a new object to store in your array. But what happens when you have an exception? Line 27 never runs, but the exception is caught in line 30 (which is inside the loop) so the loop just continues and now you have a null value in one of the array spots.

Just FYI, it's generally a bad practice to catch "Exception" as you don't know anything about the exception that was caught. You should catch specific exceptions ("ArgumentException" for example) so you can deal with it as needed.

Here's a little code snippet that may help you understand what's happening..Code from here - http://stackoverflow.com/questions/188693/is-the-destructor-called-if-the-constructor-throws-an-exception

using System;

class Test
{
    Test()
    {
        throw new Exception();
    }

    ~Test()
    {
        Console.WriteLine("Finalized");
    }

    static void Main()
    {
        try
        {
            new Test();
        }
        catch {}
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}

Thanks for your responses! The explanation that Momerath gave me an idea of why I'm getting the NullReferenceException - now I just need to figure out how to rewrite it so that my default values in Worker are used when the exception is called, rather than just setting those values to null. I'll post with an update as its available.

Gerard - I don't know too much about destructors other than using them for cleanup. Could they still be applicable if I want to reassign variables to a default value?

Just a side note* - Please forgive my ignorance as I'm still relatively new to the C# programming language. Again, thank you for your help! I'll get cracking at this again and update you all on the solution (HOPEFULLY without more questions, though additional aid is always appreciated! :-))

Thanks for your responses! The explanation that Momerath gave me an idea of why I'm getting the NullReferenceException - now I just need to figure out how to rewrite it so that my default values in Worker are used when the exception is called, rather than just setting those values to null. I'll post with an update as its available.

Gerard - I don't know too much about destructors other than using them for cleanup. Could they still be applicable if I want to reassign variables to a default value?

Just a side note* - Please forgive my ignorance as I'm still relatively new to the C# programming language. Again, thank you for your help! I'll get cracking at this again and update you all on the solution (HOPEFULLY without more questions, though additional aid is always appreciated! :-))

I think one of your problems stem from the constructor throwing an exception when one of your parameters is one of range. When the constructor throws an exception the destructor is called cleaning up the object.i.e. The object doesn't exist.

Ok, that makes sense! I didn't think of implicit destructors cleaning up my object - again, still learning this stuff!

Thanks for the clarification. Now, I just need to figure out how to reassign the values instead of cleaning them up when the exception is thrown!

Ok, that makes sense! I didn't think of implicit destructors cleaning up my object - again, still learning this stuff!

Thanks for the clarification. Now, I just need to figure out how to reassign the values instead of cleaning them up when the exception is thrown!

Usually you handle range and out of range situations without exceptions. You should be able to check for input validity before the constructor is called.

Yeah, that's what I've been trying to do, but I'm obviously missing something. I don't want to ask too much, but could someone show how I can cycle through my loop and assign the default values...or at least where in my code I can look to make said changes?

Ok, I'm going to attempt to explain what I've been doing now, and hopefully someone can steer me towards the right direction or point out what I'm doing incorrectly.

Because I'm testing for format exceptions and argument exceptions from my user input, I'll need my try statement to be included in that loop. However, no matter what I try, I can't seem to assign my default values when an exception is thrown.

I've tried putting the default values into the catch statement, but that doesn't seem to do anything. I then tried to use the if statement in Main, but unfortunately I had similar results - the objects in the array are still null.

I tried something in your code and it seems to work. I essentially knocked the x value back by one if an exception is thrown...

sing System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Exceptional
{
    class WorkerTest
    {
        static void Main(string[] args)
        {
            Worker[] workerArray = new Worker[2];

            int workerID;
            double hrSal;
			
            for (int x = 0; x < workerArray.Length; x++)
            {
                try
                {
			loadId(x, out workerID);
			loadSal(x, out hrSal);

                    workerArray[x] = new Worker(workerID, hrSal);//only reach here if no exceptions thrown
                }

                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
			--x;//knock counter back by one and start again.
                }

            }
            Console.WriteLine();
            for (int i = 0; i < workerArray.Length; i++)
            {
                Console.WriteLine("Worker # {0} \nHourly salary {1}\n--------\n ", workerArray[i].workerID, workerArray[i].hrSal.ToString("C"));
            }
        }
		private static void loadSal(int position, out double val)
		{
			Console.Write("Input an hourly Salary for the worker[{0}]: ", position);
            val = Convert.ToDouble(Console.ReadLine());
			
			if (val < 5.0 || val > 55.0)
			{
				throw new ArgumentException("Unexpected Salary Range.");
			}
		}
		
		private static void loadId(int position, out int val)
		{
			Console.Write("Input a work identification number for worker[{0}]: ", position);
            val = Convert.ToInt32(Console.ReadLine());
		}
    }

    class Worker
    {
        public int workerID;
        public double hrSal;

        public Worker(int WorkerID, double HrSal)
        {
            workerID = WorkerID;
            hrSal = HrSal;
        }
    }
}

Hmmm...it doesn't use the default values, but it does allow for the user to re-input correct values as need be, which would be a more accurate case in a realworld situation. I'm hoping thats a suitable work-around!

Thank you so much everyone for your tips, advice, and knowledge! I know I'm still a "newbie" when it comes to programming, but as my knowledge continues to increase, I plan on helping out this community just as you all took the time out of your day to help me.

I'll go ahead and mark this solution as solved for now and continue to work an alternative method of writing the code to include default values. If anyone sees this post in the future is interested in how to code the project using default values rather than rolling back the loop, feel free to send me a private message. Hopefully I'll have both methods of coding the project down by then! :)

Thanks again!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.