Reputation: 51
I am having trouble understanding how to reference an Array in this program. Every time I display the result, it will only show the last total entered. I believe this is because I am not referencing it properly? I am curious as to why, and how to avoid this in future. It seems like a simple solution, but I cannot figure it out.
public partial class frmInvoiceTotal : Form
{
public frmInvoiceTotal()
{
InitializeComponent();
total[0] = 0.0m;
total[1] = 0.0m;
total[2] = 0.0m;
total[3] = 0.0m;
total[4] = 0.0m;
}
decimal[] total = new decimal[5];
// TODO: declare class variables for array and list here
private void btnCalculate_Click(object sender, EventArgs e)
{
try
{
if (txtSubtotal.Text == "")
{
MessageBox.Show(
"Subtotal is a required field.", "Entry Error");
}
else
{
decimal subtotal = Decimal.Parse(txtSubtotal.Text);
if (subtotal > 0 && subtotal < 10000)
{
decimal discountPercent = 0m;
if (subtotal >= 500)
discountPercent = .2m;
else if (subtotal >= 250 & subtotal < 500)
discountPercent = .15m;
else if (subtotal >= 100 & subtotal < 250)
discountPercent = .1m;
decimal discountAmount = subtotal * discountPercent;
decimal invoiceTotal = subtotal - discountAmount;
discountAmount = Math.Round(discountAmount, 2);
invoiceTotal = Math.Round(invoiceTotal, 2);
txtDiscountPercent.Text = discountPercent.ToString("p1");
txtDiscountAmount.Text = discountAmount.ToString();
txtTotal.Text = invoiceTotal.ToString();
for (int i =0; i < total.Length; i++)
{
total[0] = invoiceTotal;
}
}
else
{
MessageBox.Show(
"Subtotal must be greater than 0 and less than 10,000.",
"Entry Error");
}
}
}
catch (FormatException)
{
MessageBox.Show(
"Please enter a valid number for the Subtotal field.",
"Entry Error");
}
txtSubtotal.Focus();
}
private void btnExit_Click(object sender, EventArgs e)
{
string totalsString = " ";
foreach (decimal totals in total)
totalsString += totals + "\n";
MessageBox.Show("The totals are:\n" + totalsString + "\n");
// TODO: add code that displays dialog boxes here
this.Close();
}
}
Upvotes: 0
Views: 511
Reputation: 3355
Objects in C# (.Net) are either passed by value or passed by reference.
Objects and Arrays are passed by reference by default, Value Types are not unless you specifically annotate the parameter with the ref
keyword.
To reference your array you simply need to point some variable to the location of the array , in essence when you obtain the reference to the array or allocate an instance you actually get a pointer to the memory where the instance is located.
E.g. Pointer arithmetic is considered an unverifiable concept from certain perspectives in the CLR just as some normal function calls may also be, See also What is 'unverifiable code' and why is it bad?
This essentially also reduces the learning curve on the language because such concepts can only be utilized through the use of specific keyword unsafe
and it's related scope; Pointers can also be utilized through the GCHandle
class and Marshal
classes to access memory related to an instance both managed and unmanaged alike.
This allows someone to start off not knowing a great deal about programming in general and then to be able to move into working with more advanced concepts later on even if only in a limited manner through platform invocation.
In short, you already had a reference to your array and the ValueType's within, further C# performs bounds checking for you and thus you can't access an element of an array or which does't exist in the array unless you do so using unverifiable code.
To access the reference to elements within the array you can use 'System.Runtime.InteropServices.Marshal.UnsafeAddrOfPinnedArrayElement'or you can utilize fixed
in conjunction with the subjugate array which will which will effectively skip the bounds checking done by the CLR but will also make your code unverifiable.
To access the elements in a safe way you can use the indexing mnemonic []
or methods available through the IList
interface because all Array
instances also implement such.
Finally all object
instances can potentially be stored in a single array of object
, of which is a single object
itself.
This can potentially lead to problems with inheritance depending on how your classes are designed, see Covariance and Contravariance in Generics for more information on how to avoid such pitfalls.
Upvotes: 0
Reputation: 216243
The loop that you use when you want to set the total doesn't make sense.
You set always the element at position zero for 5 times. The loop is not needed, but you need a indexer that allows you to insert the calculated invoice total in a different position of the array at each button click
So for example you could define a variable that keeps the index of the first free element in the total array
decimal[] total = new decimal[5];
int nextTotal = 0;
private void btnCalculate_Click(object sender, EventArgs e)
{
// Make sure that we don't try to set an
// inexistant position in array else 'Index out of range exception'
if(nextTotal == total.Length)
{
MessageBox.Show("Cannot add another total");
return;
}
.....
// for (int i =0; i < total.Length; i++)
// {
// total[0] = invoiceTotal;
//}
// Set the invoiceTotal to the current free slot in the array
total[nextTotal] = invoiceTotal;
// Point to the next free slot ....
nextTotal++;
....
However a better approach is to remove the array and use a List<decimal>
that has no predefined limits of elements and thus you can add at your will
List<decimal> total = new List<decimal>();
private void btnCalculate_Click(object sender, EventArgs e)
{
// You don't have a limit of 5 totals with a List but you
// could continue to add new totals unless you reach the
// end of available memory (very improbable with this)
....
total.Add(invoiceTotal);
...
}
and you can loop over the list as it was an array
foreach(decimal value in total)
Console.WriteLine(value);
Upvotes: 1
Reputation: 485
Just check
for (int i =0; i < total.Length; i++)
{
total[0] = invoiceTotal; // should be **total[i]!!!**
}
Upvotes: 0