【问题标题】:C# Class with dependent properties具有依赖属性的 C# 类
【发布时间】:2021-12-04 06:14:14
【问题描述】:

我是 C# 编程的新手,我目前正在努力解决(我认为)对于有经验的程序员来说应该是小菜一碟的代码。 我想写一个很小的应用程序来计算一个数字的税(21%):

  • 如果我定义了 exclVAT 编号,它应该返回计算出的 inclVAT 编号
  • 如果我定义了一个 inclVAT 编号,它应该返回计算出的 exclVAT 编号

我的目标是拥有这样的东西:只要您在两个框中的一个中输入值,该应用就会给出结果:

VAT utility (这将在 WPF 中使用 XAML 完成,带有 INotifyPropertyChanged 接口,但这不是我的问题的目标)。

我正在尝试使用 1 个类和 2 个属性:inclVat 和 exclVat(均为 double 类型)。但棘手的是这两个属性相互依赖。 因此,如果我将 exclVat 属性设置/更改为 100,我希望将 inclVat 属性更改为 121。如果我将 inclVat 值设置/更改为 100,我希望将 exclVat 属性更改为 0,83。

我已经想出了这段代码,但还不够,因为公共属性字段在我更改它们的值时不会改变......

班级:

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;
                
            }
        }
    }

当我执行一些任务时:

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}");

我有以下输出:

InclVat: 100
ExclVat: 82,64
Changing inclVat to 200
InclVat: 200
ExclVat: 165,29
Changing exclVat to 100
InclVat: 121
ExclVat: 165,29

一开始还可以,但是一旦我更改了 exclVat 属性,输出就不再正常了(最后 2 行)。 谁能帮我解决这个问题?

【问题讨论】:

  • 您可以编写单元测试来指定所需的行为。然后,如果出现错误,您可以使用调试器检查哪里(在哪一步)有错误的值。
  • 您可能会发现将类中的值存储为一种类型(包括或不包括)更容易,然后在需要时简单地计算另一种类型。
  • 最后两行的预期行为是什么, inclVat 和 exclVat 的值应该是什么?

标签: c# class properties dependencies


【解决方案1】:

你可以这样写:

  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})";
  }

让我们添加一些测试:

  (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);

结果:

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)

【讨论】:

  • 您好 Dmitry,非常感谢您的快速回答和解决方案。似乎我的逻辑在 setter 和 getter 上是错误的。非常感谢:-)
【解决方案2】:

当您获得ExclVat 时,您似乎想要InclVat [公共属性] 的计算值,而不是支持字段_inclVat。尝试将ExclValget 更改为

 return System.Math.Round(InclVat / 1.21, 2);

【讨论】:

  • 你好,cudima,这也成功了。非常感谢您的更新,但我会坚持 Dmitry 的回答,因为他在课堂上添加了更多逻辑:-)。
猜你喜欢
  • 1970-01-01
  • 2011-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-16
  • 2011-10-14
  • 1970-01-01
  • 2010-09-28
相关资源
最近更新 更多