I feel like I am getting close using the debugger but am still not able to figure this one out.
I am walking through the following code
namespace Taxes
{
public class Rates
{
//A class constructor that assigns default values
public Rates()
{
incLimit = 30000;
lowTaxRate = .15;
highTaxRate = .28;
}
//A class constructor that takes three parameters to assign input values for limit, low rate and high rate.
public Rates(int lim, double low, double high)
{
incLimit = lim;
lowTaxRate = low;
highTaxRate = high;
}
// A CalculateTax method that takes an income parameter and computes the tax as follows:
public int CalculateTax(int income)
{
//determine if the income is above or below the limit and calculate the tax owed based on the correct rate
int taxOwed;
if (income < incLimit)
taxOwed = Convert.ToInt32(income * lowTaxRate);
else
taxOwed = Convert.ToInt32(income * highTaxRate);
return taxOwed;
}
}
// The Taxpayer class is a comparable class
public class Taxpayer : IComparable
{
//Use get and set accessors.
private int taxOwed;
string SSN
{ set; get; }
int grossIncome
{ set; get; }
int TaxOwed {
get
{
return taxOwed;
}
}
int IComparable.CompareTo(Object o)
{
int returnVal;
Taxpayer temp = (Taxpayer)o;
if (this.taxOwed > temp.taxOwed)
returnVal = 1;
else if (this.taxOwed < temp.taxOwed)
returnVal = -1;
else returnVal = 0;
return returnVal;
}
public static Rates GetRates()
{
// Local method data members for income limit, low rate and high rate.
int incLimit;
double lowRate;
double highRate;
string userInput;
//Rates myRates = new Rates(incLimit, lowRate, highRate);
//Rates rates = new Rates();
// Prompt the user to enter a selection for either default settings or user input of settings.
Console.Write("Would you like the default values (D) or would you like to enter the values (E)?: ");
// if they want the default values or enter their own
userInput = (Console.ReadLine());
if (userInput == "D" || userInput == "d")
{
Rates myRates = new Rates();
return myRates;
//Rates.Rates();
//rates.CalculateTax(incLimit);
}
else if (userInput == "E" || userInput == "e")
{
Console.Write("Please enter the income limit: ");
incLimit = Convert.ToInt32(Console.ReadLine());
Console.Write("Please enter the low rate: ");
lowRate = Convert.ToDouble(Console.ReadLine());
Console.Write("Please enter the high rate: ");
highRate = Convert.ToDouble(Console.ReadLine());
Rates myRates = new Rates(incLimit, lowRate, highRate);
return myRates;
//rates.CalculateTax(incLimit);
}
else return null;
}
static void Main(string[] args)
{
Taxpayer[] taxArray = new Taxpayer[5];
//Rates taxRates = new Rates();
// Implement a for-loop that will prompt the user to enter the Social Security Number and gross income.
for (int x = 0; x < taxArray.Length; ++x)
{
taxArray[x] = new Taxpayer();
Console.Write("Please enter the Social Security Number for taxpayer {0}: ", x + 1);
taxArray[x].SSN = Console.ReadLine();
Console.Write("Please enter the gross income for taxpayer {0}: ", x + 1);
taxArray[x].grossIncome = Convert.ToInt32(Console.ReadLine());
//taxArray[x].taxOwed = taxRates.CalculateTax(taxArray[x].grossIncome);
}
Rates myRate = Taxpayer.GetRates();
//Taxpayer.GetRates();
// Implement a for-loop that will display each object as formatted taxpayer SSN, income and calculated tax.
for (int i = 0; i < taxArray.Length; ++i)
{
Console.WriteLine("Taxpayer # {0} SSN: {1}, Income is {2:c}, Tax is {3:c}", i + 1, taxArray[i].SSN, taxArray[i].grossIncome, myRate.CalculateTax(taxArray[i].grossIncome));//taxArray[i].taxOwed);
}
// Implement a for-loop that will sort the five objects in order by the amount of tax owed
Array.Sort(taxArray);
Console.WriteLine("Sorted by tax owed");
for (int i = 0; i < taxArray.Length; ++i)
{
//double taxes = myTax.CalculateTax(taxArray[i].grossIncome);
Console.WriteLine("Taxpayer # {0} SSN: {1}, Income is {2:c}, Tax is {3:c}", i + 1, taxArray[i].SSN, taxArray[i].grossIncome, myRate.CalculateTax(taxArray[i].grossIncome));
}
}
}
}
I have everything solved except that the sort is not sorting by the tax owed amount for some reason now.
An aside regarding
Taxpayer.GetRates(): the taxpayer class shouldn’t be responsible for determining the tax rates. If taxpayers could determine tax rates, tax rates would most likely be zero. It might make more sense to move that into theRatesclass.This answer to your question shows an example that should help you understand where you’re going wrong. If you would like a specific suggestion related to your code, please post a complete program that compiles. The sample code you’ve posted does not compile (error: “the name ‘taxRates’ does not exist in the current context”).
To answer your question:
As others have noted, you need to retain a reference to the newly instantiated object, so you can use that instance when you read the values from the fields.
Consider:
Instead, return the object you created in SetRates() (and call it GetRates() instead). Then pass it into the UseRates method:
With regard to your edited code, you have
Now
Taxpayer.GetRates()assigns some values to a Rates instance, but it’s not the same Rates instance you created with the statementRates myTax = new Rates(). The statementRates myTax = new Rates()calls the default Rates constructor, and that’s the instance that you use later in the method for calculating the tax! This explains why your tax is always calculated with the default values.The GetRates method operates on a different instance of the Rates class. That different instance is created by one of the
new Rates(...expressions in the body of the GetRates method. That instance has the rates you want to use, but it is basically trapped inside the method. Why is it trapped? Because you only assign the instance to a local variable, and local variables are not accessible outside the method in which they are declared.It’s a bit like this: instead of
Rates, we haveCar, and instead ofGetRateswe haveFillFuelTank. Your code is then doing the following:Now, the GetRates() method … I mean, the FillFuelTank method … does this:
You see what you’ve done? You’ve driven to the gas station in your new car, got a second car with fuel in it, and then you went back to the first car and drove away — without putting any fuel into it.
One solution to that would be to pass
myTaxas an argument to theGetRates()method; a better solution would be to return a Rates instance from theGetRates()method.You wrote:
The expression
new Rates()calls the default constructor. So, the way to callcalculateTaxwithout calling the default constructor is to call the parameterized constructor instead:You might say, “but I did call the parameterized constructor in the GetRates method!” And there’s the problem, again, of filling the wrong car with fuel, because the Rates object in the GetRates method is a different object. You call the parameterized constructor on the object you don’t use, and you call the default constructor on the object you do use.