-1

I have two classes Invoice and InvoiceProducts. InvoiceProducts is a collection and has a get only property called Price and I want Invoice to have a property called TotalPrice which would return the Price foreach item in the InvoiceProducts collections added to it. However I'm not sure about going about this. With the current way I'm trying to use it I get an error saying

"Object reference not set to an instance of an object." Is there a way to do this?

Current way:

public class Invoice
{
    public int InvoiceID { get; set; }
    public string ClientName { get; set; }
    public DateTime Date { get; set; } = DateTime.Today;
    private decimal totalPrice;
    public decimal TotalPrice {
        get
        {
            return totalPrice;
        }
        set
        {
            foreach(var item in InvoiceProducts)
            {
                totalPrice += item.Price;
            }
        }
    }

    public virtual ICollection<InvoiceProducts> InvoiceProducts { get; set; }
}

public class InvoiceProducts
{
    public int InvoiceProductsID { get; set; }
    public int InvoiceID { get; set; }
    public int ProductID { get; set; }
    public int ProductQuantity { get; set; }
    public decimal Price { get { return Product.ProductPrice * ProductQuantity; } }

    public virtual Invoice Invoice { get; set; }
    public virtual Product Product { get; set; }
}
FortyTwo
  • 2,414
  • 3
  • 22
  • 33
Wiliam Cardoso
  • 434
  • 1
  • 8
  • 23
  • Add init for InvoiceProducts (eg public virtual ICollection InvoiceProducts { get; set; } = new List();) – Leonid Malyshev May 29 '17 at 13:14
  • You also can delete set part for TotalPrice and use only get (of course calculating the answer before return) – Leonid Malyshev May 29 '17 at 13:16
  • Possible duplicate of [What is a NullReferenceException, and how do I fix it?](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – dymanoid May 29 '17 at 13:16

2 Answers2

3
public decimal TotalPrice {
    get
    {
        return InvoiceProducts.Sum(product => product.Price);
    }
}

or shorter, because it's get only:

public decimal TotalPrice => InvoiceProducts.Sum(product => product.Price);

And of course you need to initialize your list of products and probably make it get only.

public Invoice() 
{
    InvoiceProducts = new List<InvoiceProcuct>();
}

public ICollection<InvoiceProduct> InvoiceProducts { get; }
S. Spindler
  • 546
  • 3
  • 12
0

I see that this is already answered, but I wanted to provide some additional clarification, if I might try. A set takes parameters, and is special logic that you want to run whenever you assign the value of a property, based on what you're assigning it to. To take a simple example:

  public class SpecialNumber
    {
        private double _theNumber; 

        public double TheNumber
        {
            get { return _theNumber; }
            set
            {
                _theNumber = value * Math.PI;
            }
        }
    }

The reserved word value is the right-hand-side of the expression:

specialNumberObject.TheNumber = 5.0;

As such, value will take on 5.0 inside the setter. The logic you had inside your setter as indicated by S. Spindler is perfect for a get, since it defines a custom return that you want to have executed whenever we want to access the value of a property.

Another version of my class might decide to have a property that multiplies by PI on the way out, which might be useful if the back-end logic in my class relied on the number being its' unmultiplied form. In that case, the logic would be more appropriate for a getter.

I hope I didn't confuse the issue.