ADT for a TVM calculator I wanted to get some criticism for the below ADT. This is just a basic ADT that will be fed into a TVM calculator. Main purpose is to have it initialized and correct for input errors.

Full disclosure: I am modeling it after Code Complete 2 guidelines. You should notice if statements stating nominal cases first followed by error-checking in else statements. I am trying to come as close as possible to the guidelines in the book. However, it is difficult to grasp 900+ pages of material. Aside from the incompleteness of the class, what am I missing, or what would Code Complete 2 catch?

public class TVMData
{
public decimal DiscountRate;
public decimal PeriodLength;
public decimal CashFlowFromAsset;
public decimal CashOutFlow;   
public decimal PaymentFrequency;  

   decimal DiscountedCashFlow;

    public TVMData(){}

    public TVMData(double discountRate, double periodLength, double cashFlowFromAsset, double cashOutFlow, PaymentPerPeriod paymentFrequency= PaymentPerPeriod.Annual)
      : this(Convert.ToDecimal(discountRate), Convert.ToDecimal(periodLength), Convert.ToDecimal(cashFlowFromAsset), Convert.ToDecimal(cashOutFlow), paymentFrequency){}

    public TVMData (decimal discountRate, decimal periodLength, decimal cashFlowFromAsset, decimal cashOutFlow, PaymentPerPeriod paymentFrequency= PaymentPerPeriod.Annual)
    {
        this.PaymentFrequency = Convert.ToDecimal(paymentFrequency);

        if (discountRate&gt;=0m) 
        {
           this.DiscountRate= discountRate;

            if (periodLength &gt;= 1m)
            {
                this.PeriodLength = periodLength;

                if(cashFlowFromAsset &gt;= 0m)
                {

                 this.CashFlowFromAsset=cashFlowFromAsset;

                   if(cashOutFlow &lt;= 0m)
                   {

                    this.CashOutFlow = cashOutFlow;

                   }

                   else
                   {
                    throw new ArgumentOutOfRangeException("Cash Out Flow must be less than or equal to Zero", "cashOutFlow");
                   }

                }

                else
                {
                throw new ArgumentOutOfRangeException("Cash Flow From Asset must be greater than Zero","cashFlowFromAsset");
                }

            }

            else
            {
            throw new ArgumentOutOfRangeException("Period Length must be equal or greater than One", "periodLength");
            }

        }

        else
        {
         throw new ArgumentOutOfRangeException("Discount Rate must be greater than Zero", "discountRate");
        }


     }

}
That book is a little dated in some of its recommendation (although still a great book).  That particular IF-ELSE recommendation leads to the ArrowCode anti-pattern, a better way (at least it reduces congnitive load) would be to use Guarded Clauses (see here too)

public TVMData(decimal discountRate, decimal periodLength, decimal cashFlowFromAsset, decimal cashOutFlow, PaymentPerPeriod paymentFrequency = PaymentPerPeriod.Annual)
        {
            if (discountRate &lt; 0m)
                throw new ArgumentOutOfRangeException("Discount Rate must be greater than Zero", "discountRate");
            if (periodLength &lt; 1m)
                throw new ArgumentOutOfRangeException("Period Length must be equal or greater than One", "periodLength");
            if (cashFlowFromAsset &lt; 0m)
                throw new ArgumentOutOfRangeException("Cash Flow From Asset must be greater than Zero", "cashFlowFromAsset");
            if (cashOutFlow &gt; 0m)
                throw new ArgumentOutOfRangeException("Cash Out Flow must be less than or equal to Zero", "cashOutFlow");

            this.DiscountRate = discountRate;
            this.PaymentFrequency = Convert.ToDecimal(paymentFrequency);
            this.PeriodLength = periodLength;
            this.CashFlowFromAsset = cashFlowFromAsset;
            this.CashOutFlow = cashOutFlow;
        }


Your Code here converts double to decimal, you may have issues with calling functions not taking into account the smaller range decimal has when compared to double

public TVMData(double discountRate, double periodLength, double cashFlowFromAsset, double cashOutFlow, PaymentPerPeriod paymentFrequency= PaymentPerPeriod.Annual)
      : this(Convert.ToDecimal(discountRate), Convert.ToDecimal(periodLength), Convert.ToDecimal(cashFlowFromAsset), Convert.ToDecimal(cashOutFlow), paymentFrequency){}


I would also move these to private if I could.  Reducing the scope and visibility of data leads to more reliable/maintainable code by reducing coupling (see here for better argument or here).

public decimal DiscountRate;
public decimal PeriodLength;
public decimal CashFlowFromAsset;
public decimal CashOutFlow;   
public decimal PaymentFrequency;