I'm very new to C# programming, and I'm currently struggling with what should be (I think) a piece of cake code for experienced programmers. I want to write a very little app to calculate a tax (21%) on a number:
- If I define an exclVAT number, it should return the calculated inclVAT number
- If I define an inclVAT number, it should return the calculated exclVAT number
My goal is to have something like this: an app that gives the results as soon as you type a value in one of the two boxes:
VAT utility (This will be done in WPF using XAML, with an INotifyPropertyChanged interface, but this is not the goal of my question).
I'm trying to do this with 1 class, and 2 properties: inclVat and exclVat (both as type double). But the tricky thing is that both properties depend on each other. So if I set/change the exclVat property to 100, I want to have the inclVat property to be changed to 121. And if I set/change the inclVat value to 100, I want the exclVat property changed to 0,83.
I already come up with this code, but is is not sufficient, as the public property fields don't change when I change the values on them...
The Class:
public class Vat
{
private double _inclVat;
public double InclVat
{
get
{
if (_ExclVat == 0)
{
return _inclVat;
}
else
{
return (_ExclVat * 1.21);
}
}
set
{
_inclVat = value;
}
}
private double _ExclVat;
public double ExclVat
{
get
{
return System.Math.Round(_inclVat / 1.21, 2);
}
set
{
_ExclVat = value;
}
}
}
And when I run it with some assignments:
Vat Number = new Vat();
Number.InclVat = 100;
System.Console.WriteLine($"InclVat: {Number.InclVat}");
System.Console.WriteLine($"ExclVat: {Number.ExclVat}");
System.Console.WriteLine("Changing inclVat to 200");
Number.InclVat = 200;
System.Console.WriteLine($"InclVat: {Number.InclVat}");
System.Console.WriteLine($"ExclVat: {Number.ExclVat}");
System.Console.WriteLine("Changing exclVat to 100");
Number.ExclVat = 100;
System.Console.WriteLine($"InclVat: {Number.InclVat}");
System.Console.WriteLine($"ExclVat: {Number.ExclVat}");
I have the following output:
InclVat: 100
ExclVat: 82,64
Changing inclVat to 200
InclVat: 200
ExclVat: 165,29
Changing exclVat to 100
InclVat: 121
ExclVat: 165,29
In the beginning it's ok, but as soon as I change the exclVat property, the output isn't ok anymore (last 2 lines). Can anyone help me with this?
CodePudding user response:
You can put something like this:
public class Vat {
private decimal m_IncludeVat; // <- decimal is a better choice for finance
// To compute VAT we should know the percent; let it be known
public const decimal Percent = 18.0m;
public decimal IncludeVat {
get => m_IncludeVat;
set {
// negative cash are usually invalid; if it's not the case, drop this check
if (value < 0)
throw new ArgumentOutOfRangeException(nameof(value));
m_IncludeVat = value;
Tax = Math.Round(m_IncludeVat / 100 * Percent, 2);
}
}
public decimal ExcludeVat {
get => m_IncludeVat - Tax;
set {
if (value < 0)
throw new ArgumentOutOfRangeException(nameof(value));
m_IncludeVat = Math.Round(value / (100 - Percent) * 100, 2);
Tax = m_IncludeVat - value;
}
}
// Let's be nice and provide Tax value as well as IncludeVat, ExcludeVat
public decimal Tax {get; private set;}
public override string ToString() =>
$"Include: {IncludeVat:f2}; exclude: {ExcludeVat:f2} (tax: {Tax:f2})";
}
Let's add some tests:
(decimal cash, bool isInclude)[] tests = new (decimal cash, bool isInclude)[] {
(100, true),
(200, true),
(100, false),
(121.95m, true)
};
var report = string.Join(Environment.NewLine, tests
.Select(test => {
Vat num = new Vat();
if (test.isInclude)
num.IncludeVat = test.cash;
else
num.ExcludeVat = test.cash;
return num;
}));
Console.WriteLine(report);
Outcome:
Include: 100,00; exclude: 82,00 (tax: 18,00)
Include: 200,00; exclude: 164,00 (tax: 36,00)
Include: 121,95; exclude: 100,00 (tax: 21,95)
Include: 121,95; exclude: 100,00 (tax: 21,95)
CodePudding user response:
it seems like you want the computed value of InclVat
[the public property], not the backing field _inclVat
when you are getting ExclVat
. Try changing ExclVal
's get
to
return System.Math.Round(InclVat / 1.21, 2);